Moved application logic into Core which are now 'Sections'. Have proxied all calls from the legacy application to sections. Streamlined how automapper configs are registered (much better now). Updated some unit tests to use the new classes instead of the legacy ones. Created the sections controller to return the sections from the back office. Changed the TypeFinder to search all types not just public ones, changed the boot managers to not have to explicitly modify the resolvers with internal types because now internal types are automatically found.
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.ObjectResolution;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
@@ -100,9 +103,19 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// This method allows for configuration of model mappers
|
||||
/// </summary>
|
||||
protected virtual void InitializeModelMappers()
|
||||
/// <remarks>
|
||||
/// Model mappers MUST be defined on ApplicationEventHandler instances with the interface IMapperConfiguration.
|
||||
/// This allows us to search for less types on startup.
|
||||
/// </remarks>
|
||||
protected void InitializeModelMappers()
|
||||
{
|
||||
//TODO: There will most likely be AutoMapper configs to put in here, we know they exist in web for now so we'll leave this here for future use
|
||||
Mapper.Initialize(configuration =>
|
||||
{
|
||||
foreach (var m in ApplicationEventsResolver.Current.ApplicationEventHandlers.OfType<IMapperConfiguration>())
|
||||
{
|
||||
m.ConfigureMappings(configuration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,8 +148,6 @@ namespace Umbraco.Core
|
||||
{
|
||||
CanResolveBeforeFrozen = true
|
||||
};
|
||||
//add custom types here that are internal
|
||||
ApplicationEventsResolver.Current.AddType<PublishedContentHelper>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -280,10 +291,6 @@ namespace Umbraco.Core
|
||||
|
||||
PropertyEditorValueConvertersResolver.Current = new PropertyEditorValueConvertersResolver(
|
||||
PluginManager.Current.ResolvePropertyEditorValueConverters());
|
||||
//add the internal ones, these are not public currently so need to add them manually
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<DatePickerPropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<TinyMcePropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<YesNoPropertyEditorValueConverter>();
|
||||
|
||||
// this is how we'd switch over to DefaultShortStringHelper _and_ still use
|
||||
// UmbracoSettings UrlReplaceCharacters...
|
||||
|
||||
@@ -7,9 +7,9 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
internal static class ModelMapperHelper
|
||||
{
|
||||
internal static IMappingExpression<TSource, TSource> SelfMap<TSource>()
|
||||
internal static IMappingExpression<TSource, TSource> SelfMap<TSource>(this IConfiguration config)
|
||||
{
|
||||
return Mapper.CreateMap<TSource, TSource>();
|
||||
return config.CreateMap<TSource, TSource>();
|
||||
}
|
||||
}
|
||||
}
|
||||
22
src/Umbraco.Core/Models/Mapping/IMapperConfiguration.cs
Normal file
22
src/Umbraco.Core/Models/Mapping/IMapperConfiguration.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
|
||||
namespace Umbraco.Core.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to explicitly decorate any ApplicationEventHandler class if there are
|
||||
/// AutoMapper configurations defined.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All automapper configurations are done during startup
|
||||
/// inside an Automapper Initialize call which is better for performance
|
||||
/// </remarks>
|
||||
internal interface IMapperConfiguration : IApplicationEventHandler
|
||||
{
|
||||
void ConfigureMappings(IConfiguration config);
|
||||
}
|
||||
}
|
||||
15
src/Umbraco.Core/Models/Mapping/MapperConfiguration.cs
Normal file
15
src/Umbraco.Core/Models/Mapping/MapperConfiguration.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using AutoMapper;
|
||||
|
||||
namespace Umbraco.Core.Models.Mapping
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to declare a mapper configuration
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Use this class if your mapper configuration isn't also explicitly an ApplicationEventHandler.
|
||||
/// </remarks>
|
||||
internal abstract class MapperConfiguration : ApplicationEventHandler, IMapperConfiguration
|
||||
{
|
||||
public abstract void ConfigureMappings(IConfiguration config);
|
||||
}
|
||||
}
|
||||
23
src/Umbraco.Core/Sections/Section.cs
Normal file
23
src/Umbraco.Core/Sections/Section.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
namespace Umbraco.Core.Sections
|
||||
{
|
||||
public class Section
|
||||
{
|
||||
public Section(string name, string @alias, string icon, int sortOrder)
|
||||
{
|
||||
Name = name;
|
||||
Alias = alias;
|
||||
Icon = icon;
|
||||
SortOrder = sortOrder;
|
||||
}
|
||||
|
||||
public Section()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public string Name { get; set; }
|
||||
public string Alias { get; set; }
|
||||
public string Icon { get; set; }
|
||||
public int SortOrder { get; set; }
|
||||
}
|
||||
}
|
||||
202
src/Umbraco.Core/Sections/SectionCollection.cs
Normal file
202
src/Umbraco.Core/Sections/SectionCollection.cs
Normal file
@@ -0,0 +1,202 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Trees;
|
||||
|
||||
namespace Umbraco.Core.Sections
|
||||
{
|
||||
public class SectionCollection
|
||||
{
|
||||
internal const string AppConfigFileName = "applications.config";
|
||||
private static string _appConfig;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// gets/sets the application.config file path
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath
|
||||
/// </remarks>
|
||||
internal static string AppConfigFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_appConfig))
|
||||
{
|
||||
_appConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + AppConfigFileName);
|
||||
}
|
||||
return _appConfig;
|
||||
}
|
||||
set { _appConfig = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The cache storage for all applications
|
||||
/// </summary>
|
||||
internal static IEnumerable<Section> Sections
|
||||
{
|
||||
get
|
||||
{
|
||||
return ApplicationContext.Current.ApplicationCache.GetCacheItem(
|
||||
CacheKeys.ApplicationsCacheKey,
|
||||
() =>
|
||||
{
|
||||
////used for unit tests
|
||||
//if (_testApps != null)
|
||||
// return _testApps;
|
||||
|
||||
var tmp = new List<Section>();
|
||||
|
||||
LoadXml(doc =>
|
||||
{
|
||||
foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
|
||||
{
|
||||
var sortOrderAttr = x.Attribute("sortOrder");
|
||||
return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
|
||||
}))
|
||||
{
|
||||
var sortOrderAttr = addElement.Attribute("sortOrder");
|
||||
tmp.Add(new Section(addElement.Attribute("name").Value,
|
||||
addElement.Attribute("alias").Value,
|
||||
addElement.Attribute("icon").Value,
|
||||
sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
|
||||
}
|
||||
|
||||
}, false);
|
||||
return tmp;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal static void LoadXml(Action<XDocument> callback, bool saveAfterCallback)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
var doc = File.Exists(AppConfigFilePath)
|
||||
? XDocument.Load(AppConfigFilePath)
|
||||
: XDocument.Parse("<?xml version=\"1.0\"?><applications />");
|
||||
|
||||
if (doc.Root != null)
|
||||
{
|
||||
callback.Invoke(doc);
|
||||
|
||||
if (saveAfterCallback)
|
||||
{
|
||||
//ensure the folder is created!
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath));
|
||||
|
||||
doc.Save(AppConfigFilePath);
|
||||
|
||||
//remove the cache so it gets re-read ... SD: I'm leaving this here even though it
|
||||
// is taken care of by events as well, I think unit tests may rely on it being cleared here.
|
||||
ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the application by its alias.
|
||||
/// </summary>
|
||||
/// <param name="appAlias">The application alias.</param>
|
||||
/// <returns></returns>
|
||||
public static Section GetByAlias(string appAlias)
|
||||
{
|
||||
return Sections.FirstOrDefault(t => t.Alias == appAlias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new applcation if no application with the specified alias is found.
|
||||
/// </summary>
|
||||
/// <param name="name">The application name.</param>
|
||||
/// <param name="alias">The application alias.</param>
|
||||
/// <param name="icon">The application icon, which has to be located in umbraco/images/tray folder.</param>
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static void MakeNew(string name, string alias, string icon)
|
||||
{
|
||||
MakeNew(name, alias, icon, Sections.Max(x => x.SortOrder) + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Makes the new.
|
||||
/// </summary>
|
||||
/// <param name="name">The name.</param>
|
||||
/// <param name="alias">The alias.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <param name="sortOrder">The sort order.</param>
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static void MakeNew(string name, string alias, string icon, int sortOrder)
|
||||
{
|
||||
if (Sections.All(x => x.Alias != alias))
|
||||
{
|
||||
LoadXml(doc =>
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("alias", alias),
|
||||
new XAttribute("name", name),
|
||||
new XAttribute("icon", icon),
|
||||
new XAttribute("sortOrder", sortOrder)));
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnNew(new Section(name, alias, icon, sortOrder), new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes the section
|
||||
/// </summary>
|
||||
public static void DeleteSection(Section section)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
//delete the assigned applications
|
||||
ApplicationContext.Current.DatabaseContext.Database.Execute(
|
||||
"delete from umbracoUser2App where app = @appAlias",
|
||||
new { appAlias = section.Alias });
|
||||
|
||||
//delete the assigned trees
|
||||
var trees = ApplicationTreeCollection.GetApplicationTree(section.Alias);
|
||||
foreach (var t in trees)
|
||||
{
|
||||
ApplicationTreeCollection.DeleteTree(t);
|
||||
}
|
||||
|
||||
LoadXml(doc =>
|
||||
{
|
||||
doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == section.Alias).Remove();
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnDeleted(section, new EventArgs());
|
||||
}
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Section, EventArgs> Deleted;
|
||||
private static void OnDeleted(Section app, EventArgs args)
|
||||
{
|
||||
if (Deleted != null)
|
||||
{
|
||||
Deleted(app, args);
|
||||
}
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Section, EventArgs> New;
|
||||
private static void OnNew(Section app, EventArgs args)
|
||||
{
|
||||
if (New != null)
|
||||
{
|
||||
New(app, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -211,6 +211,8 @@
|
||||
<Compile Include="Models\IDictionaryTranslation.cs" />
|
||||
<Compile Include="Models\IFile.cs" />
|
||||
<Compile Include="Models\ILanguage.cs" />
|
||||
<Compile Include="Models\Mapping\IMapperConfiguration.cs" />
|
||||
<Compile Include="Models\Mapping\MapperConfiguration.cs" />
|
||||
<Compile Include="Models\Membership\UmbracoMembershipUser.cs" />
|
||||
<Compile Include="Models\ServerRegistration.cs" />
|
||||
<Compile Include="Models\ITemplate.cs" />
|
||||
@@ -688,6 +690,8 @@
|
||||
<Compile Include="Publishing\PublishStatus.cs" />
|
||||
<Compile Include="Publishing\PublishStatusType.cs" />
|
||||
<Compile Include="RenderingEngine.cs" />
|
||||
<Compile Include="Sections\Section.cs" />
|
||||
<Compile Include="Sections\SectionCollection.cs" />
|
||||
<Compile Include="Serialization\AbstractSerializationService.cs" />
|
||||
<Compile Include="Serialization\Formatter.cs" />
|
||||
<Compile Include="Serialization\IFormatter.cs" />
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using AutoMapper;
|
||||
using NUnit.Framework;
|
||||
using SqlCE4Umbraco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Sections;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using umbraco.BusinessLogic;
|
||||
using umbraco.DataLayer;
|
||||
@@ -33,12 +36,25 @@ namespace Umbraco.Tests.BusinessLogic
|
||||
public void Initialize()
|
||||
{
|
||||
ApplicationContext.Current = new ApplicationContext(false){IsReady = true};
|
||||
InitializeMappers();
|
||||
InitializeDatabase();
|
||||
InitializeApps();
|
||||
InitializeAppConfigFile();
|
||||
InitializeTreeConfigFile();
|
||||
}
|
||||
|
||||
private void InitializeMappers()
|
||||
{
|
||||
Mapper.Initialize(configuration =>
|
||||
{
|
||||
var mappers = PluginManager.Current.FindAndCreateInstances<IMapperConfiguration>();
|
||||
foreach (var mapper in mappers)
|
||||
{
|
||||
mapper.ConfigureMappings(configuration);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void ClearDatabase()
|
||||
{
|
||||
var databaseSettings = ConfigurationManager.ConnectionStrings[Core.Configuration.GlobalSettings.UmbracoConnectionName];
|
||||
@@ -71,7 +87,7 @@ namespace Umbraco.Tests.BusinessLogic
|
||||
|
||||
private void InitializeApps()
|
||||
{
|
||||
Application.MakeNew("content", "content", "file", 0);
|
||||
SectionCollection.MakeNew("content", "content", "file", 0);
|
||||
//Application.SetTestApps(new List<Application>()
|
||||
// {
|
||||
// new Application(Constants.Applications.Content, "content", "content", 0)
|
||||
@@ -80,7 +96,7 @@ namespace Umbraco.Tests.BusinessLogic
|
||||
|
||||
private void InitializeAppConfigFile()
|
||||
{
|
||||
Application.AppConfigFilePath = IOHelper.MapPath(SystemDirectories.Config + "/" + Application.AppConfigFileName, false);
|
||||
SectionCollection.AppConfigFilePath = IOHelper.MapPath(SystemDirectories.Config + "/" + SectionCollection.AppConfigFileName, false);
|
||||
}
|
||||
|
||||
private void InitializeTreeConfigFile()
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
<Prefer32Bit>false</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="AutoMapper, Version=2.2.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\AutoMapper.2.2.1\lib\net40\AutoMapper.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Examine, Version=0.1.51.2941, Culture=neutral, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\packages\Examine.0.1.51.2941\lib\Examine.dll</HintPath>
|
||||
@@ -288,8 +292,8 @@
|
||||
<Compile Include="Publishing\PublishingStrategyTests.cs" />
|
||||
<Compile Include="Resolvers\ActionsResolverTests.cs" />
|
||||
<Compile Include="AsynchronousRollingFileAppenderTests.cs" />
|
||||
<Compile Include="BusinessLogic\ApplicationTest.cs" />
|
||||
<Compile Include="BusinessLogic\ApplicationTreeTest.cs" />
|
||||
<Compile Include="TreesAndSections\SectionTests.cs" />
|
||||
<Compile Include="TreesAndSections\ApplicationTreeTest.cs" />
|
||||
<Compile Include="BusinessLogic\BaseTest.cs" />
|
||||
<Compile Include="CacheRefresherFactoryTests.cs" />
|
||||
<Compile Include="PublishedContent\DynamicPublishedContentCustomExtensionMethods.cs" />
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="AutoMapper" version="2.2.1" targetFramework="net45" />
|
||||
<package id="Examine" version="0.1.51.2941" targetFramework="net40" />
|
||||
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
|
||||
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net40" />
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @ngdoc factory
|
||||
* @name umbraco.resources.section
|
||||
* @description Loads in data for section
|
||||
**/
|
||||
function sectionResource($q, $http) {
|
||||
|
||||
/** internal method to get the tree app url */
|
||||
function getSectionsUrl(section) {
|
||||
return Umbraco.Sys.ServerVariables.sectionApiBaseUrl + "GetSections";
|
||||
}
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
/** Loads in the data to display the section list */
|
||||
getSections: function (options) {
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
//go and get the tree data
|
||||
$http.get(getSectionsUrl()).
|
||||
success(function (data, status, headers, config) {
|
||||
deferred.resolve(data);
|
||||
}).
|
||||
error(function (data, status, headers, config) {
|
||||
deferred.reject('Failed to retreive data for sections');
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('treeResource', treeResource);
|
||||
@@ -2558,7 +2558,6 @@
|
||||
<Folder Include="Media\" />
|
||||
<Folder Include="Scripts\" />
|
||||
<Folder Include="Umbraco\assets\" />
|
||||
<Folder Include="Umbraco\lib\" />
|
||||
<Folder Include="Umbraco_Client\FolderBrowser\Images\" />
|
||||
<Folder Include="Umbraco_Client\Tags\images\" />
|
||||
<Folder Include="UserControls\" />
|
||||
|
||||
@@ -3,6 +3,7 @@ using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using Umbraco.Core.Sections;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Trees;
|
||||
using umbraco;
|
||||
@@ -30,8 +31,8 @@ namespace Umbraco.Web.Cache
|
||||
ApplicationTreeCollection.New += ApplicationTreeNew;
|
||||
|
||||
//bind to application events
|
||||
Application.Deleted += ApplicationDeleted;
|
||||
Application.New += ApplicationNew;
|
||||
SectionCollection.Deleted += ApplicationDeleted;
|
||||
SectionCollection.New += ApplicationNew;
|
||||
|
||||
//bind to user type events
|
||||
UserType.Deleted += UserTypeDeleted;
|
||||
@@ -145,12 +146,12 @@ namespace Umbraco.Web.Cache
|
||||
#endregion
|
||||
|
||||
#region Application event handlers
|
||||
static void ApplicationNew(Application sender, System.EventArgs e)
|
||||
static void ApplicationNew(Section sender, System.EventArgs e)
|
||||
{
|
||||
DistributedCache.Instance.RefreshAllApplicationCache();
|
||||
}
|
||||
|
||||
static void ApplicationDeleted(Application sender, System.EventArgs e)
|
||||
static void ApplicationDeleted(Section sender, System.EventArgs e)
|
||||
{
|
||||
DistributedCache.Instance.RefreshAllApplicationCache();
|
||||
}
|
||||
|
||||
@@ -58,7 +58,8 @@ namespace Umbraco.Web.Editors
|
||||
{"umbracoPath", GlobalSettings.Path},
|
||||
{"contentApiBaseUrl", Url.GetUmbracoApiService<ContentController>("PostSave").TrimEnd("PostSave")},
|
||||
{"mediaApiBaseUrl", Url.GetUmbracoApiService<MediaController>("GetRootMedia").TrimEnd("GetRootMedia")},
|
||||
{"treeApplicationApiBaseUrl", Url.GetUmbracoApiService<ApplicationTreeApiController>("GetTreeData").TrimEnd("GetTreeData")},
|
||||
{"sectionApiBaseUrl", Url.GetUmbracoApiService<SectionController>("GetSections").TrimEnd("GetSections")},
|
||||
{"treeApplicationApiBaseUrl", Url.GetUmbracoApiService<ApplicationTreeController>("GetApplicationTrees").TrimEnd("GetApplicationTrees")},
|
||||
{"contentTypeApiBaseUrl", Url.GetUmbracoApiService<ContentTypeController>("GetAllowedChildren").TrimEnd("GetAllowedChildren")},
|
||||
{"mediaTypeApiBaseUrl", Url.GetUmbracoApiService<MediaTypeApiController>("GetAllowedChildren").TrimEnd("GetAllowedChildren")},
|
||||
{"authenticationApiBaseUrl", Url.GetUmbracoApiService<AuthenticationController>("PostLogin").TrimEnd("PostLogin")}
|
||||
|
||||
21
src/Umbraco.Web/Editors/SectionController.cs
Normal file
21
src/Umbraco.Web/Editors/SectionController.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using AutoMapper;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using System.Linq;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// The API controller used for using the list of sections
|
||||
/// </summary>
|
||||
[PluginController("UmbracoApi")]
|
||||
public class SectionController : UmbracoAuthorizedApiController
|
||||
{
|
||||
public IEnumerable<Section> GetSections()
|
||||
{
|
||||
return Core.Sections.SectionCollection.Sections.Select(Mapper.Map<Core.Sections.Section, Section>);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
src/Umbraco.Web/Models/ContentEditing/Section.cs
Normal file
28
src/Umbraco.Web/Models/ContentEditing/Section.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents a section (application) in the back office
|
||||
/// </summary>
|
||||
[DataContract(Name = "section", Namespace = "")]
|
||||
public class Section
|
||||
{
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "cssclass")]
|
||||
public string CssClass { get; set; }
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
15
src/Umbraco.Web/Models/Mapping/SectionModelMapper.cs
Normal file
15
src/Umbraco.Web/Models/Mapping/SectionModelMapper.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class SectionModelMapper : MapperConfiguration
|
||||
{
|
||||
public override void ConfigureMappings(IConfiguration config)
|
||||
{
|
||||
config.CreateMap<Section, Umbraco.Core.Sections.Section>()
|
||||
.ReverseMap(); //backwards too!
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,27 @@
|
||||
using System;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
internal class UserModelMapper
|
||||
internal class UserModelMapper : MapperConfiguration
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures the automapper mappings
|
||||
/// </summary>
|
||||
internal static void Configure()
|
||||
|
||||
#region Mapper config
|
||||
public override void ConfigureMappings(IConfiguration config)
|
||||
{
|
||||
Mapper.CreateMap<IUser, UserDetail>()
|
||||
config.CreateMap<IUser, UserDetail>()
|
||||
.ForMember(detail => detail.UserId, opt => opt.MapFrom(user => GetIntId(user.Id)))
|
||||
.ForMember(
|
||||
detail => detail.EmailHash,
|
||||
opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5()));
|
||||
Mapper.CreateMap<IProfile, UserBasic>()
|
||||
config.CreateMap<IProfile, UserBasic>()
|
||||
.ForMember(detail => detail.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id)));
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
private static int GetIntId(object id)
|
||||
{
|
||||
@@ -41,6 +42,6 @@ namespace Umbraco.Web.Models.Mapping
|
||||
public UserBasic ToUserBasic(IProfile profile)
|
||||
{
|
||||
return Mapper.Map<UserBasic>(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,123 +1,123 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Management.Instrumentation;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Trees;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
|
||||
[PluginController("UmbracoTrees")]
|
||||
public class ApplicationTreeApiController : UmbracoAuthorizedApiController
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Remove the xml formatter... only support JSON!
|
||||
/// </summary>
|
||||
/// <param name="controllerContext"></param>
|
||||
protected override void Initialize(global::System.Web.Http.Controllers.HttpControllerContext controllerContext)
|
||||
{
|
||||
base.Initialize(controllerContext);
|
||||
controllerContext.Configuration.Formatters.Remove(controllerContext.Configuration.Formatters.XmlFormatter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the tree nodes for an application
|
||||
/// </summary>
|
||||
/// <param name="application"></param>
|
||||
/// <param name="queryStrings"></param>
|
||||
/// <returns></returns>
|
||||
[HttpQueryStringFilter("queryStrings")]
|
||||
public TreeNodeCollection GetApplicationTrees(string application, FormDataCollection queryStrings)
|
||||
{
|
||||
if (application == null) throw new ArgumentNullException("application");
|
||||
|
||||
//find all tree definitions that have the current application alias
|
||||
var appTrees = ApplicationTreeCollection.GetApplicationTree(application).Where(x => x.Initialize).ToArray();
|
||||
if (appTrees.Count() == 1)
|
||||
{
|
||||
//return the nodes for the one tree assigned
|
||||
return GetNodeCollection(appTrees.Single(), "-1", queryStrings);
|
||||
}
|
||||
|
||||
var collection = new TreeNodeCollection();
|
||||
foreach (var tree in appTrees)
|
||||
{
|
||||
//return the root nodes for each tree in the app
|
||||
var rootNode = GetRoot(tree, queryStrings);
|
||||
collection.Add(rootNode);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the tree data for a specific tree for the children of the id
|
||||
/// </summary>
|
||||
/// <param name="treeType"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="queryStrings"></param>
|
||||
/// <returns></returns>
|
||||
[HttpQueryStringFilter("queryStrings")]
|
||||
public TreeNodeCollection GetTreeData(string treeType, string id, FormDataCollection queryStrings)
|
||||
{
|
||||
if (treeType == null) throw new ArgumentNullException("treeType");
|
||||
|
||||
//get the configured tree
|
||||
var foundConfigTree = ApplicationTreeCollection.GetByAlias(treeType);
|
||||
if (foundConfigTree == null)
|
||||
throw new InstanceNotFoundException("Could not find tree of type " + treeType + " in the trees.config");
|
||||
|
||||
return GetNodeCollection(foundConfigTree, id, queryStrings);
|
||||
}
|
||||
|
||||
private TreeNode GetRoot(ApplicationTree configTree, FormDataCollection queryStrings)
|
||||
{
|
||||
if (configTree == null) throw new ArgumentNullException("configTree");
|
||||
var byControllerAttempt = configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext, Request);
|
||||
if (byControllerAttempt.Success)
|
||||
{
|
||||
return byControllerAttempt.Result;
|
||||
}
|
||||
var legacyAttempt = configTree.TryGetRootNodeFromLegacyTree(queryStrings, Url);
|
||||
if (legacyAttempt.Success)
|
||||
{
|
||||
return legacyAttempt.Result;
|
||||
}
|
||||
|
||||
throw new ApplicationException("Could not get root node for tree type " + configTree.Alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the node collection for the tree, try loading from new controllers first, then from legacy trees
|
||||
/// </summary>
|
||||
/// <param name="configTree"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="queryStrings"></param>
|
||||
/// <returns></returns>
|
||||
private TreeNodeCollection GetNodeCollection(ApplicationTree configTree, string id, FormDataCollection queryStrings)
|
||||
{
|
||||
if (configTree == null) throw new ArgumentNullException("configTree");
|
||||
var byControllerAttempt = configTree.TryLoadFromControllerTree(id, queryStrings, ControllerContext, Request);
|
||||
if (byControllerAttempt.Success)
|
||||
{
|
||||
return byControllerAttempt.Result;
|
||||
}
|
||||
var legacyAttempt = configTree.TryLoadFromLegacyTree(id, queryStrings, Url);
|
||||
if (legacyAttempt.Success)
|
||||
{
|
||||
return legacyAttempt.Result;
|
||||
}
|
||||
|
||||
throw new ApplicationException("Could not render a tree for type " + configTree.Alias);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Management.Instrumentation;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Trees;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
|
||||
[PluginController("UmbracoTrees")]
|
||||
public class ApplicationTreeController : UmbracoAuthorizedApiController
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Remove the xml formatter... only support JSON!
|
||||
/// </summary>
|
||||
/// <param name="controllerContext"></param>
|
||||
protected override void Initialize(global::System.Web.Http.Controllers.HttpControllerContext controllerContext)
|
||||
{
|
||||
base.Initialize(controllerContext);
|
||||
controllerContext.Configuration.Formatters.Remove(controllerContext.Configuration.Formatters.XmlFormatter);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the tree nodes for an application
|
||||
/// </summary>
|
||||
/// <param name="application"></param>
|
||||
/// <param name="queryStrings"></param>
|
||||
/// <returns></returns>
|
||||
[HttpQueryStringFilter("queryStrings")]
|
||||
public TreeNodeCollection GetApplicationTrees(string application, FormDataCollection queryStrings)
|
||||
{
|
||||
if (application == null) throw new ArgumentNullException("application");
|
||||
|
||||
//find all tree definitions that have the current application alias
|
||||
var appTrees = ApplicationTreeCollection.GetApplicationTree(application).Where(x => x.Initialize).ToArray();
|
||||
if (appTrees.Count() == 1)
|
||||
{
|
||||
//return the nodes for the one tree assigned
|
||||
return GetNodeCollection(appTrees.Single(), "-1", queryStrings);
|
||||
}
|
||||
|
||||
var collection = new TreeNodeCollection();
|
||||
foreach (var tree in appTrees)
|
||||
{
|
||||
//return the root nodes for each tree in the app
|
||||
var rootNode = GetRoot(tree, queryStrings);
|
||||
collection.Add(rootNode);
|
||||
}
|
||||
return collection;
|
||||
}
|
||||
|
||||
///// <summary>
|
||||
///// Returns the tree data for a specific tree for the children of the id
|
||||
///// </summary>
|
||||
///// <param name="treeType"></param>
|
||||
///// <param name="id"></param>
|
||||
///// <param name="queryStrings"></param>
|
||||
///// <returns></returns>
|
||||
//[HttpQueryStringFilter("queryStrings")]
|
||||
//public TreeNodeCollection GetTreeData(string treeType, string id, FormDataCollection queryStrings)
|
||||
//{
|
||||
// if (treeType == null) throw new ArgumentNullException("treeType");
|
||||
|
||||
// //get the configured tree
|
||||
// var foundConfigTree = ApplicationTreeCollection.GetByAlias(treeType);
|
||||
// if (foundConfigTree == null)
|
||||
// throw new InstanceNotFoundException("Could not find tree of type " + treeType + " in the trees.config");
|
||||
|
||||
// return GetNodeCollection(foundConfigTree, id, queryStrings);
|
||||
//}
|
||||
|
||||
private TreeNode GetRoot(ApplicationTree configTree, FormDataCollection queryStrings)
|
||||
{
|
||||
if (configTree == null) throw new ArgumentNullException("configTree");
|
||||
var byControllerAttempt = configTree.TryGetRootNodeFromControllerTree(queryStrings, ControllerContext, Request);
|
||||
if (byControllerAttempt.Success)
|
||||
{
|
||||
return byControllerAttempt.Result;
|
||||
}
|
||||
var legacyAttempt = configTree.TryGetRootNodeFromLegacyTree(queryStrings, Url);
|
||||
if (legacyAttempt.Success)
|
||||
{
|
||||
return legacyAttempt.Result;
|
||||
}
|
||||
|
||||
throw new ApplicationException("Could not get root node for tree type " + configTree.Alias);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the node collection for the tree, try loading from new controllers first, then from legacy trees
|
||||
/// </summary>
|
||||
/// <param name="configTree"></param>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="queryStrings"></param>
|
||||
/// <returns></returns>
|
||||
private TreeNodeCollection GetNodeCollection(ApplicationTree configTree, string id, FormDataCollection queryStrings)
|
||||
{
|
||||
if (configTree == null) throw new ArgumentNullException("configTree");
|
||||
var byControllerAttempt = configTree.TryLoadFromControllerTree(id, queryStrings, ControllerContext, Request);
|
||||
if (byControllerAttempt.Success)
|
||||
{
|
||||
return byControllerAttempt.Result;
|
||||
}
|
||||
var legacyAttempt = configTree.TryLoadFromLegacyTree(id, queryStrings, Url);
|
||||
if (legacyAttempt.Success)
|
||||
{
|
||||
return legacyAttempt.Result;
|
||||
}
|
||||
|
||||
throw new ApplicationException("Could not render a tree for type " + configTree.Alias);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -298,10 +298,12 @@
|
||||
<Compile Include="Editors\AuthenticationController.cs" />
|
||||
<Compile Include="Editors\ContentController.cs" />
|
||||
<Compile Include="Editors\ContentTypeController.cs" />
|
||||
<Compile Include="Editors\SectionController.cs" />
|
||||
<Compile Include="HttpCookieExtensions.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentSaveAction.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentTypeBasic.cs" />
|
||||
<Compile Include="Models\ContentEditing\MediaItemDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\Section.cs" />
|
||||
<Compile Include="Models\ContentEditing\Tab.cs" />
|
||||
<Compile Include="Models\ContentEditing\TabbedContentItem.cs" />
|
||||
<Compile Include="Models\ContentEditing\UserBasic.cs" />
|
||||
@@ -311,6 +313,7 @@
|
||||
<Compile Include="FormDataCollectionExtensions.cs" />
|
||||
<Compile Include="Models\Mapping\ContentTypeModelMapper.cs" />
|
||||
<Compile Include="Models\Mapping\MediaModelMapper.cs" />
|
||||
<Compile Include="Models\Mapping\SectionModelMapper.cs" />
|
||||
<Compile Include="Models\Mapping\UserModelMapper.cs" />
|
||||
<Compile Include="PropertyEditors\ContentPickerPropertyEditor.cs" />
|
||||
<Compile Include="PropertyEditors\FileUploadPropertyEditor.cs" />
|
||||
@@ -331,7 +334,7 @@
|
||||
<Compile Include="Trees\TreeNode.cs" />
|
||||
<Compile Include="Trees\TreeNodeCollection.cs" />
|
||||
<Compile Include="Trees\TreeQueryStringParameters.cs" />
|
||||
<Compile Include="Trees\ApplicationTreeApiController.cs" />
|
||||
<Compile Include="Trees\ApplicationTreeController.cs" />
|
||||
<Compile Include="Editors\BackOfficeController.cs" />
|
||||
<Compile Include="Security\Providers\MembersMembershipProvider.cs" />
|
||||
<Compile Include="Security\Providers\UsersMembershipProvider.cs" />
|
||||
|
||||
@@ -112,23 +112,12 @@ namespace Umbraco.Web
|
||||
ProfilerResolver.Current.SetProfiler(new WebProfiler());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the model mappers
|
||||
/// </summary>
|
||||
protected override void InitializeModelMappers()
|
||||
{
|
||||
base.InitializeModelMappers();
|
||||
UserModelMapper.Configure();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds custom types to the ApplicationEventsResolver
|
||||
/// </summary>
|
||||
protected override void InitializeApplicationEventsResolver()
|
||||
{
|
||||
base.InitializeApplicationEventsResolver();
|
||||
ApplicationEventsResolver.Current.AddType<CacheHelperExtensions.CacheHelperApplicationEventListener>();
|
||||
ApplicationEventsResolver.Current.AddType<LegacyScheduledTasks>();
|
||||
//We need to remove these types because we've obsoleted them and we don't want them executing:
|
||||
ApplicationEventsResolver.Current.RemoveType<global::umbraco.LibraryCacheRefresher>();
|
||||
}
|
||||
@@ -291,10 +280,10 @@ namespace Umbraco.Web
|
||||
UmbracoApiControllerResolver.Current = new UmbracoApiControllerResolver(
|
||||
PluginManager.Current.ResolveUmbracoApiControllers());
|
||||
|
||||
//the base creates the PropertyEditorValueConvertersResolver but we want to modify it in the web app and replace
|
||||
//the TinyMcePropertyEditorValueConverter with the RteMacroRenderingPropertyEditorValueConverter
|
||||
PropertyEditorValueConvertersResolver.Current.RemoveType<TinyMcePropertyEditorValueConverter>();
|
||||
PropertyEditorValueConvertersResolver.Current.AddType<RteMacroRenderingPropertyEditorValueConverter>();
|
||||
//the base creates the PropertyEditorValueConvertersResolver but we want to modify it in the web app and remove
|
||||
//the TinyMcePropertyEditorValueConverter since when the web app is loaded the RteMacroRenderingPropertyEditorValueConverter
|
||||
//is found and we'll use that instead.
|
||||
PropertyEditorValueConvertersResolver.Current.RemoveType<TinyMcePropertyEditorValueConverter>();
|
||||
|
||||
PublishedCachesResolver.Current = new PublishedCachesResolver(new PublishedCaches(
|
||||
new PublishedCache.XmlPublishedCache.PublishedContentCache(),
|
||||
|
||||
@@ -5,11 +5,13 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Sections;
|
||||
using umbraco.DataLayer;
|
||||
using System.Runtime.CompilerServices;
|
||||
using umbraco.businesslogic;
|
||||
@@ -19,88 +21,18 @@ namespace umbraco.BusinessLogic
|
||||
/// <summary>
|
||||
/// Class for handling all registered applications in Umbraco.
|
||||
/// </summary>
|
||||
[Obsolete("Use Umbraco.Core.Sections.SectionCollection instead")]
|
||||
public class Application
|
||||
{
|
||||
private static ISqlHelper _sqlHelper;
|
||||
|
||||
internal const string AppConfigFileName = "applications.config";
|
||||
private static string _appConfig;
|
||||
private static readonly object Locker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// gets/sets the application.config file path
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The setter is generally only going to be used in unit tests, otherwise it will attempt to resolve it using the IOHelper.MapPath
|
||||
/// </remarks>
|
||||
internal static string AppConfigFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_appConfig))
|
||||
{
|
||||
_appConfig = IOHelper.MapPath(SystemDirectories.Config + "/" + AppConfigFileName);
|
||||
}
|
||||
return _appConfig;
|
||||
}
|
||||
set { _appConfig = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The cache storage for all applications
|
||||
/// </summary>
|
||||
internal static List<Application> Apps
|
||||
{
|
||||
get
|
||||
{
|
||||
return ApplicationContext.Current.ApplicationCache.GetCacheItem(
|
||||
CacheKeys.ApplicationsCacheKey,
|
||||
() =>
|
||||
{
|
||||
////used for unit tests
|
||||
//if (_testApps != null)
|
||||
// return _testApps;
|
||||
|
||||
var tmp = new List<Application>();
|
||||
|
||||
try
|
||||
{
|
||||
LoadXml(doc =>
|
||||
{
|
||||
foreach (var addElement in doc.Root.Elements("add").OrderBy(x =>
|
||||
{
|
||||
var sortOrderAttr = x.Attribute("sortOrder");
|
||||
return sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0;
|
||||
}))
|
||||
{
|
||||
var sortOrderAttr = addElement.Attribute("sortOrder");
|
||||
tmp.Add(new Application(addElement.Attribute("name").Value,
|
||||
addElement.Attribute("alias").Value,
|
||||
addElement.Attribute("icon").Value,
|
||||
sortOrderAttr != null ? Convert.ToInt32(sortOrderAttr.Value) : 0));
|
||||
}
|
||||
|
||||
}, false);
|
||||
return tmp;
|
||||
}
|
||||
catch
|
||||
{
|
||||
//this is a bit of a hack that just ensures the application doesn't crash when the
|
||||
//installer is run and there is no database or connection string defined.
|
||||
//the reason this method may get called during the installation is that the
|
||||
//SqlHelper of this class is shared amongst everything "Application" wide.
|
||||
|
||||
//TODO: Perhaps we should log something here??
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SQL helper.
|
||||
/// </summary>
|
||||
/// <value>The SQL helper.</value>
|
||||
[Obsolete("Do not use SqlHelper anymore, if database querying needs to be done use the DatabaseContext instead")]
|
||||
public static ISqlHelper SqlHelper
|
||||
{
|
||||
get
|
||||
@@ -197,10 +129,9 @@ namespace umbraco.BusinessLogic
|
||||
/// <param name="name">The application name.</param>
|
||||
/// <param name="alias">The application alias.</param>
|
||||
/// <param name="icon">The application icon, which has to be located in umbraco/images/tray folder.</param>
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static void MakeNew(string name, string alias, string icon)
|
||||
{
|
||||
MakeNew(name, alias, icon, Apps.Max(x => x.sortOrder) + 1);
|
||||
SectionCollection.MakeNew(name, alias, icon);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -210,25 +141,9 @@ namespace umbraco.BusinessLogic
|
||||
/// <param name="alias">The alias.</param>
|
||||
/// <param name="icon">The icon.</param>
|
||||
/// <param name="sortOrder">The sort order.</param>
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static void MakeNew(string name, string alias, string icon, int sortOrder)
|
||||
{
|
||||
var exist = getAll().Any(x => x.alias == alias);
|
||||
|
||||
if (!exist)
|
||||
{
|
||||
LoadXml(doc =>
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("alias", alias),
|
||||
new XAttribute("name", name),
|
||||
new XAttribute("icon", icon),
|
||||
new XAttribute("sortOrder", sortOrder)));
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnNew(new Application(name, alias, icon, sortOrder), new EventArgs());
|
||||
}
|
||||
SectionCollection.MakeNew(name, alias, icon, sortOrder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -238,7 +153,8 @@ namespace umbraco.BusinessLogic
|
||||
/// <returns></returns>
|
||||
public static Application getByAlias(string appAlias)
|
||||
{
|
||||
return Apps.Find(t => t.alias == appAlias);
|
||||
return Mapper.Map<Section, Application>(
|
||||
SectionCollection.GetByAlias(appAlias));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -246,23 +162,7 @@ namespace umbraco.BusinessLogic
|
||||
/// </summary>
|
||||
public void Delete()
|
||||
{
|
||||
//delete the assigned applications
|
||||
SqlHelper.ExecuteNonQuery("delete from umbracoUser2App where app = @appAlias", SqlHelper.CreateParameter("@appAlias", this.alias));
|
||||
|
||||
//delete the assigned trees
|
||||
var trees = ApplicationTree.getApplicationTree(this.alias);
|
||||
foreach (var t in trees)
|
||||
{
|
||||
t.Delete();
|
||||
}
|
||||
|
||||
LoadXml(doc =>
|
||||
{
|
||||
doc.Root.Elements("add").Where(x => x.Attribute("alias") != null && x.Attribute("alias").Value == this.alias).Remove();
|
||||
}, true);
|
||||
|
||||
//raise event
|
||||
OnDeleted(this, new EventArgs());
|
||||
SectionCollection.DeleteSection(Mapper.Map<Application, Section>(this));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -271,7 +171,7 @@ namespace umbraco.BusinessLogic
|
||||
/// <returns>Returns a Application Array</returns>
|
||||
public static List<Application> getAll()
|
||||
{
|
||||
return Apps;
|
||||
return SectionCollection.Sections.Select(Mapper.Map<Section, Application>).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -283,49 +183,6 @@ namespace umbraco.BusinessLogic
|
||||
ApplicationStartupHandler.RegisterHandlers();
|
||||
}
|
||||
|
||||
internal static void LoadXml(Action<XDocument> callback, bool saveAfterCallback)
|
||||
{
|
||||
lock (Locker)
|
||||
{
|
||||
var doc = File.Exists(AppConfigFilePath)
|
||||
? XDocument.Load(AppConfigFilePath)
|
||||
: XDocument.Parse("<?xml version=\"1.0\"?><applications />");
|
||||
|
||||
if (doc.Root != null)
|
||||
{
|
||||
callback.Invoke(doc);
|
||||
|
||||
if (saveAfterCallback)
|
||||
{
|
||||
//ensure the folder is created!
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(AppConfigFilePath));
|
||||
|
||||
doc.Save(AppConfigFilePath);
|
||||
|
||||
//remove the cache so it gets re-read ... SD: I'm leaving this here even though it
|
||||
// is taken care of by events as well, I think unit tests may rely on it being cleared here.
|
||||
ApplicationContext.Current.ApplicationCache.ClearCacheItem(CacheKeys.ApplicationsCacheKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Application, EventArgs> Deleted;
|
||||
private static void OnDeleted(Application app, EventArgs args)
|
||||
{
|
||||
if (Deleted != null)
|
||||
{
|
||||
Deleted(app, args);
|
||||
}
|
||||
}
|
||||
|
||||
internal static event TypedEventHandler<Application, EventArgs> New;
|
||||
private static void OnNew(Application app, EventArgs args)
|
||||
{
|
||||
if (New != null)
|
||||
{
|
||||
New(app, args);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,11 @@ using System.Configuration;
|
||||
using System.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Sections;
|
||||
using umbraco.BusinessLogic.Utils;
|
||||
using umbraco.DataLayer;
|
||||
using umbraco.businesslogic;
|
||||
@@ -12,75 +15,47 @@ using umbraco.interfaces;
|
||||
|
||||
namespace umbraco.BusinessLogic
|
||||
{
|
||||
public class ApplicationRegistrar : IApplicationStartupHandler
|
||||
public class ApplicationRegistrar : ApplicationEventHandler, IMapperConfiguration
|
||||
{
|
||||
private ISqlHelper _sqlHelper;
|
||||
protected ISqlHelper SqlHelper
|
||||
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
get
|
||||
// Load all Applications by attribute and add them to the XML config
|
||||
var types = PluginManager.Current.ResolveApplications();
|
||||
|
||||
//since applications don't populate their metadata from the attribute and because it is an interface,
|
||||
//we need to interrogate the attributes for the data. Would be better to have a base class that contains
|
||||
//metadata populated by the attribute. Oh well i guess.
|
||||
var attrs = types.Select(x => x.GetCustomAttributes<ApplicationAttribute>(false).Single())
|
||||
.Where(x => SectionCollection.GetByAlias(x.Alias) == null)
|
||||
.ToArray();
|
||||
|
||||
var allAliases = SectionCollection.Sections.Select(x => x.Alias).Concat(attrs.Select(x => x.Alias));
|
||||
|
||||
SectionCollection.LoadXml(doc =>
|
||||
{
|
||||
if (_sqlHelper == null)
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var databaseSettings = ConfigurationManager.ConnectionStrings[Umbraco.Core.Configuration.GlobalSettings.UmbracoConnectionName];
|
||||
_sqlHelper = DataLayerHelper.CreateSqlHelper(databaseSettings.ConnectionString, false);
|
||||
}
|
||||
catch { }
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("alias", attr.Alias),
|
||||
new XAttribute("name", attr.Name),
|
||||
new XAttribute("icon", attr.Icon),
|
||||
new XAttribute("sortOrder", attr.SortOrder)));
|
||||
}
|
||||
return _sqlHelper;
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
public ApplicationRegistrar()
|
||||
public void ConfigureMappings(IConfiguration config)
|
||||
{
|
||||
|
||||
//don't do anything if the application is not configured!
|
||||
if (!ApplicationContext.Current.IsConfigured)
|
||||
return;
|
||||
|
||||
// Load all Applications by attribute and add them to the XML config
|
||||
var types = PluginManager.Current.ResolveApplications();
|
||||
|
||||
//since applications don't populate their metadata from the attribute and because it is an interface,
|
||||
//we need to interrogate the attributes for the data. Would be better to have a base class that contains
|
||||
//metadata populated by the attribute. Oh well i guess.
|
||||
var attrs = types.Select(x => x.GetCustomAttributes<ApplicationAttribute>(false).Single())
|
||||
.Where(x => Application.getByAlias(x.Alias) == null);
|
||||
|
||||
var allAliases = Application.getAll().Select(x => x.alias).Concat(attrs.Select(x => x.Alias));
|
||||
var inString = "'" + string.Join("','", allAliases) + "'";
|
||||
|
||||
Application.LoadXml(doc =>
|
||||
{
|
||||
foreach (var attr in attrs)
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("alias", attr.Alias),
|
||||
new XAttribute("name", attr.Name),
|
||||
new XAttribute("icon", attr.Icon),
|
||||
new XAttribute("sortOrder", attr.SortOrder)));
|
||||
}
|
||||
|
||||
var db = ApplicationContext.Current.DatabaseContext.Database;
|
||||
var exist = db.TableExist("umbracoApp");
|
||||
if (exist)
|
||||
{
|
||||
var dbApps = SqlHelper.ExecuteReader("SELECT * FROM umbracoApp WHERE appAlias NOT IN (" + inString + ")");
|
||||
while (dbApps.Read())
|
||||
{
|
||||
doc.Root.Add(new XElement("add",
|
||||
new XAttribute("alias", dbApps.GetString("appAlias")),
|
||||
new XAttribute("name", dbApps.GetString("appName")),
|
||||
new XAttribute("icon", dbApps.GetString("appIcon")),
|
||||
new XAttribute("sortOrder", dbApps.GetByte("sortOrder"))));
|
||||
}
|
||||
}
|
||||
|
||||
}, true);
|
||||
|
||||
//TODO Shouldn't this be enabled and then delete the whole table?
|
||||
//SqlHelper.ExecuteNonQuery("DELETE FROM umbracoApp");
|
||||
config.CreateMap<Umbraco.Core.Sections.Section, Application>()
|
||||
.ForMember(x => x.alias, expression => expression.MapFrom(x => x.Alias))
|
||||
.ForMember(x => x.icon, expression => expression.MapFrom(x => x.Icon))
|
||||
.ForMember(x => x.name, expression => expression.MapFrom(x => x.Name))
|
||||
.ForMember(x => x.sortOrder, expression => expression.MapFrom(x => x.SortOrder)).ReverseMap();
|
||||
config.CreateMap<Application, Umbraco.Core.Sections.Section>()
|
||||
.ForMember(x => x.Alias, expression => expression.MapFrom(x => x.alias))
|
||||
.ForMember(x => x.Icon, expression => expression.MapFrom(x => x.icon))
|
||||
.ForMember(x => x.Name, expression => expression.MapFrom(x => x.name))
|
||||
.ForMember(x => x.SortOrder, expression => expression.MapFrom(x => x.sortOrder));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using umbraco.businesslogic;
|
||||
@@ -17,21 +18,20 @@ namespace umbraco.BusinessLogic
|
||||
/// <summary>
|
||||
/// A startup handler for dealing with trees
|
||||
/// </summary>
|
||||
public class ApplicationTreeRegistrar : ApplicationEventHandler
|
||||
public class ApplicationTreeRegistrar : ApplicationEventHandler, IMapperConfiguration
|
||||
{
|
||||
|
||||
protected override void ApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
|
||||
{
|
||||
ConfigureMappings();
|
||||
ScanTrees();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configures automapper model mappings
|
||||
/// </summary>
|
||||
private static void ConfigureMappings()
|
||||
public void ConfigureMappings(IConfiguration config)
|
||||
{
|
||||
Mapper.CreateMap<Umbraco.Core.Trees.ApplicationTree, ApplicationTree>()
|
||||
config.CreateMap<Umbraco.Core.Trees.ApplicationTree, ApplicationTree>()
|
||||
.ReverseMap(); //two way
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user