Merge pull request #4332 from umbraco/temp8-macros-dont-render-and-other-macro-bugs

v8 Macros don't render in the RTE and various
This commit is contained in:
Bjarke Berg
2019-02-04 13:23:46 +01:00
committed by GitHub
88 changed files with 801 additions and 1231 deletions

View File

@@ -2,6 +2,7 @@
using System.Linq;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Security;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -17,12 +18,15 @@ using Umbraco.Web.WebApi;
using Umbraco.Core.Strings;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Tests.PublishedContent;
using Umbraco.Tests.Testing;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web.Runtime;
using Umbraco.Web.Security;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Tests.Routing
@@ -136,7 +140,16 @@ namespace Umbraco.Tests.Routing
var type = new AutoPublishedContentType(22, "CustomDocument", new PublishedPropertyType[] { });
ContentTypesCache.GetPublishedContentTypeByAlias = alias => type;
var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContext, Mock.Of<ILogger>()));
var handler = new RenderRouteHandler(umbracoContext, new TestControllerFactory(umbracoContext, Mock.Of<ILogger>(), context =>
{
var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>());
return new CustomDocumentController(Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
new UmbracoHelper(umbracoContext, Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper));
}));
handler.GetHandlerForRoute(umbracoContext.HttpContext.Request.RequestContext, frequest);
Assert.AreEqual("CustomDocument", routeData.Values["controller"].ToString());
@@ -172,8 +185,8 @@ namespace Umbraco.Tests.Routing
/// </summary>
public class CustomDocumentController : RenderMvcController
{
public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger)
public CustomDocumentController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper)
{
}

View File

@@ -7,16 +7,16 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
{
public class TestControllerActivator : TestControllerActivatorBase
{
private readonly Func<HttpRequestMessage, UmbracoHelper, ApiController> _factory;
private readonly Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> _factory;
public TestControllerActivator(Func<HttpRequestMessage, UmbracoHelper, ApiController> factory)
public TestControllerActivator(Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> factory)
{
_factory = factory;
}
protected override ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoHelper helper)
protected override ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoContext umbracoContext, UmbracoHelper helper)
{
return _factory(msg, helper);
return _factory(msg, umbracoContext, helper);
}
}
}

View File

@@ -152,17 +152,16 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
var membershipHelper = new MembershipHelper(new TestUmbracoContextAccessor(umbCtx), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>());
var umbHelper = new UmbracoHelper(umbCtx,
Mock.Of<IPublishedContent>(),
var umbHelper = new UmbracoHelper(umbCtx,
Mock.Of<ITagQuery>(),
Mock.Of<ICultureDictionary>(),
Mock.Of<ICultureDictionaryFactory>(),
Mock.Of<IUmbracoComponentRenderer>(),
membershipHelper,
serviceContext);
Mock.Of<IPublishedContentQuery>(),
membershipHelper);
return CreateController(controllerType, request, umbHelper);
return CreateController(controllerType, request, umbCtx, umbHelper);
}
protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoHelper helper);
protected abstract ApiController CreateController(Type controllerType, HttpRequestMessage msg, UmbracoContext umbracoContext, UmbracoHelper helper);
}
}

View File

@@ -15,9 +15,9 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
{
public class TestRunner
{
private readonly Func<HttpRequestMessage, UmbracoHelper, ApiController> _controllerFactory;
private readonly Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> _controllerFactory;
public TestRunner(Func<HttpRequestMessage, UmbracoHelper, ApiController> controllerFactory)
public TestRunner(Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> controllerFactory)
{
_controllerFactory = controllerFactory;
}

View File

@@ -16,10 +16,10 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
/// </summary>
public class TestStartup
{
private readonly Func<HttpRequestMessage, UmbracoHelper, ApiController> _controllerFactory;
private readonly Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> _controllerFactory;
private readonly Action<HttpConfiguration> _initialize;
public TestStartup(Action<HttpConfiguration> initialize, Func<HttpRequestMessage, UmbracoHelper, ApiController> controllerFactory)
public TestStartup(Action<HttpConfiguration> initialize, Func<HttpRequestMessage, UmbracoContext, UmbracoHelper, ApiController> controllerFactory)
{
_controllerFactory = controllerFactory;
_initialize = initialize;

View File

@@ -19,6 +19,7 @@ namespace Umbraco.Tests.TestHelpers.Stubs
{
private readonly UmbracoContext _umbracoContext;
private readonly ILogger _logger;
private readonly Func<RequestContext, IController> _factory;
public TestControllerFactory(UmbracoContext umbracoContext, ILogger logger)
{
@@ -26,8 +27,17 @@ namespace Umbraco.Tests.TestHelpers.Stubs
_logger = logger;
}
public TestControllerFactory(UmbracoContext umbracoContext, ILogger logger, Func<RequestContext, IController> factory)
{
_umbracoContext = umbracoContext;
_logger = logger;
_factory = factory;
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
if (_factory != null) return _factory(requestContext);
var types = TypeFinder.FindClassesOfType<ControllerBase>(new[] { Assembly.GetExecutingAssembly() });
var controllerTypes = types.Where(x => x.Name.Equals(controllerName + "Controller", StringComparison.InvariantCultureIgnoreCase));

View File

@@ -61,12 +61,11 @@ namespace Umbraco.Tests.Testing.TestingTests
// ReSharper disable once UnusedVariable
var helper = new UmbracoHelper(umbracoContext,
Mock.Of<IPublishedContent>(),
Mock.Of<ITagQuery>(),
Mock.Of<ICultureDictionary>(),
Mock.Of<ICultureDictionaryFactory>(),
Mock.Of<IUmbracoComponentRenderer>(),
new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>()),
ServiceContext.CreatePartial());
Mock.Of<IPublishedContentQuery>(),
new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>()));
Assert.Pass();
}

View File

@@ -38,9 +38,11 @@ using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web.Actions;
using Umbraco.Web.Composing.Composers;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Macros;
using Umbraco.Web.PublishedCache;
using Current = Umbraco.Core.Composing.Current;
using Umbraco.Web.Routing;
using Umbraco.Web.Templates;
using Umbraco.Web.Trees;
namespace Umbraco.Tests.Testing
@@ -228,6 +230,7 @@ namespace Umbraco.Tests.Testing
.Append<MembersBackOfficeSection>()
.Append<TranslationBackOfficeSection>();
Composition.RegisterUnique<ISectionService, SectionService>();
}
protected virtual void ComposeWtf()

View File

@@ -30,6 +30,11 @@ using System;
using Umbraco.Web.WebApi;
using Umbraco.Web.Trees;
using System.Globalization;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Web.Actions;
namespace Umbraco.Tests.Web.Controllers
@@ -207,17 +212,28 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async Task PostSave_Validate_Existing_Content()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => null); //do not find it
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(PublishJsonInvariant),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
@@ -233,21 +249,31 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async Task PostSave_Validate_At_Least_One_Variant_Flagged_For_Saving()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent());
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
//remove all save flaggs
((JArray)json["variants"])[0]["save"] = false;
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
@@ -264,14 +290,24 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async Task PostSave_Validate_Properties_Exist()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
contentServiceMock.Setup(x => x.GetById(123)).Returns(() => GetMockedContent());
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
@@ -284,7 +320,7 @@ namespace Umbraco.Tests.Web.Controllers
value = "hello"
}));
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
@@ -298,7 +334,7 @@ namespace Umbraco.Tests.Web.Controllers
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
@@ -310,11 +346,21 @@ namespace Umbraco.Tests.Web.Controllers
contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType());
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(PublishJsonInvariant),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
@@ -332,7 +378,7 @@ namespace Umbraco.Tests.Web.Controllers
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
@@ -344,15 +390,25 @@ namespace Umbraco.Tests.Web.Controllers
contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType());
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
//clear out the name
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonInvariant);
json["variants"].ElementAt(0)["name"] = null;
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),
@@ -370,7 +426,7 @@ namespace Umbraco.Tests.Web.Controllers
{
var content = GetMockedContent();
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var contentServiceMock = Mock.Get(Current.Services.ContentService);
@@ -382,15 +438,25 @@ namespace Umbraco.Tests.Web.Controllers
contentTypeServiceMock.Setup(x => x.Get(content.ContentTypeId)).Returns(() => MockedContentTypes.CreateSimpleContentType());
var propertyEditorCollection = new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<DataEditor>()));
var usersController = new ContentController(propertyEditorCollection);
return usersController;
var controller = new ContentController(
propertyEditorCollection,
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return controller;
}
//clear out one of the names
var json = JsonConvert.DeserializeObject<JObject>(PublishJsonVariant);
json["variants"].ElementAt(0)["name"] = null;
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Content", "PostSave", HttpMethod.Post,
content: GetMultiPartRequestContent(JsonConvert.SerializeObject(json)),
mediaTypeHeader: new MediaTypeWithQualityHeaderValue("multipart/form-data"),

View File

@@ -54,7 +54,7 @@ namespace Umbraco.Tests.Web.Controllers
public class Plugin1Controller : PluginController
{
public Plugin1Controller(UmbracoContext umbracoContext)
: base(umbracoContext, null, null, null, null, null)
: base(umbracoContext, null, null, null, null, null, null)
{
}
}
@@ -63,7 +63,7 @@ namespace Umbraco.Tests.Web.Controllers
public class Plugin2Controller : PluginController
{
public Plugin2Controller(UmbracoContext umbracoContext)
: base(umbracoContext, null, null, null, null, null)
: base(umbracoContext, null, null, null, null, null, null)
{
}
}
@@ -72,7 +72,7 @@ namespace Umbraco.Tests.Web.Controllers
public class Plugin3Controller : PluginController
{
public Plugin3Controller(UmbracoContext umbracoContext)
: base(umbracoContext, null, null, null, null, null)
: base(umbracoContext, null, null, null, null, null, null)
{
}
}
@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Web.Controllers
public class Plugin4Controller : PluginController
{
public Plugin4Controller(UmbracoContext umbracoContext)
: base(umbracoContext, null, null, null, null, null)
: base(umbracoContext, null, null, null, null, null, null)
{
}
}

View File

@@ -7,9 +7,13 @@ using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
@@ -49,7 +53,7 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async System.Threading.Tasks.Task Save_User()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
//setup some mocks
Umbraco.Core.Configuration.GlobalSettings.HasSmtpServer = true;
@@ -68,7 +72,15 @@ namespace Umbraco.Tests.Web.Controllers
userServiceMock.Setup(service => service.GetUserById(It.IsAny<int>()))
.Returns((int id) => id == 1234 ? new User(1234, "Test", "test@test.com", "test@test.com", "", new List<IReadOnlyUserGroup>(), new int[0], new int[0]) : null);
var usersController = new UsersController();
var usersController = new UsersController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
@@ -82,7 +94,7 @@ namespace Umbraco.Tests.Web.Controllers
UserGroups = new[] { "writers" }
};
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "PostSaveUser", HttpMethod.Post,
new ObjectContent<UserSave>(userSave, new JsonMediaTypeFormatter()));
var obj = JsonConvert.DeserializeObject<UserDisplay>(response.Item2);
@@ -122,15 +134,23 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async System.Threading.Tasks.Task GetPagedUsers_Empty()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
var usersController = new UsersController();
var usersController = new UsersController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
MockForGetPagedUsers();
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
@@ -140,7 +160,7 @@ namespace Umbraco.Tests.Web.Controllers
[Test]
public async System.Threading.Tasks.Task GetPagedUsers_10()
{
ApiController Factory(HttpRequestMessage message, UmbracoHelper helper)
ApiController CtrlFactory(HttpRequestMessage message, UmbracoContext umbracoContext, UmbracoHelper helper)
{
//setup some mocks
var userServiceMock = Mock.Get(Current.Services.UserService);
@@ -151,13 +171,21 @@ namespace Umbraco.Tests.Web.Controllers
It.IsAny<UserState[]>(), It.IsAny<string[]>(), It.IsAny<string[]>(), It.IsAny<IQuery<IUser>>()))
.Returns(() => users);
var usersController = new UsersController();
var usersController = new UsersController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContext,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
MockForGetPagedUsers();
var runner = new TestRunner(Factory);
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);

View File

@@ -77,42 +77,15 @@ namespace Umbraco.Tests.Web.Mvc
Assert.IsNotNull(ctrl.UmbracoContext);
}
[Test]
public void Umbraco_Helper_Not_Null()
{
var globalSettings = TestObjects.GetGlobalSettings();
var umbracoContext = UmbracoContext.EnsureContext(
Current.UmbracoContextAccessor,
new Mock<HttpContextBase>().Object,
Mock.Of<IPublishedSnapshotService>(),
new Mock<WebSecurity>(null, null, globalSettings).Object,
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
globalSettings,
new TestVariationContextAccessor(),
true);
var controller = new TestSurfaceController(umbracoContext);
Composition.Register(_ => umbracoContext);
Assert.IsNotNull(controller.Umbraco);
}
[Test]
public void Can_Lookup_Content()
{
var publishedSnapshot = new Mock<IPublishedSnapshot>();
publishedSnapshot.Setup(x => x.Members).Returns(Mock.Of<IPublishedMemberCache>());
var contentCache = new Mock<IPublishedContentCache>();
var content = new Mock<IPublishedContent>();
content.Setup(x => x.Id).Returns(2);
contentCache.Setup(x => x.GetById(It.IsAny<int>())).Returns(content.Object);
var mediaCache = new Mock<IPublishedMediaCache>();
publishedSnapshot.Setup(x => x.Content).Returns(contentCache.Object);
publishedSnapshot.Setup(x => x.Media).Returns(mediaCache.Object);
var publishedSnapshotService = new Mock<IPublishedSnapshotService>();
publishedSnapshotService.Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(publishedSnapshot.Object);
var globalSettings = TestObjects.GetGlobalSettings();
var umbracoContext = UmbracoContext.EnsureContext(
@@ -128,17 +101,17 @@ namespace Umbraco.Tests.Web.Mvc
var helper = new UmbracoHelper(
umbracoContext,
Mock.Of<IPublishedContent>(),
Mock.Of<ITagQuery>(),
Mock.Of<ICultureDictionary>(),
Mock.Of<ICultureDictionaryFactory>(),
Mock.Of<IUmbracoComponentRenderer>(),
new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>()),
ServiceContext.CreatePartial());
Mock.Of<IPublishedContentQuery>(query => query.Content(2) == content.Object),
new MembershipHelper(new TestUmbracoContextAccessor(umbracoContext), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>()));
var ctrl = new TestSurfaceController(umbracoContext, helper);
var result = ctrl.GetContent(2) as PublishedContentResult;
Assert.IsNotNull(result);
Assert.IsNotNull(result.Content);
Assert.AreEqual(2, result.Content.Id);
}
@@ -185,12 +158,8 @@ namespace Umbraco.Tests.Web.Mvc
public class TestSurfaceController : SurfaceController
{
public TestSurfaceController(UmbracoContext ctx, UmbracoHelper helper = null)
: base(ctx, null, ServiceContext.CreatePartial(), Mock.Of<AppCaches>(), null, null)
: base(ctx, null, ServiceContext.CreatePartial(), Mock.Of<AppCaches>(), null, null, helper)
{
if (helper != null)
{
Umbraco = helper;
}
}
public ActionResult Index()

View File

@@ -15598,9 +15598,9 @@
}
},
"tinymce": {
"version": "4.9.0",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.0.tgz",
"integrity": "sha512-hrPeCLXY/sVCo3i64CTW8P5xbDiEI8Uii/vWpcmQWAMhex6GWWd2U+L8WIMj5tKKGdfcIQAJfpfQthc/92bcKw=="
"version": "4.9.2",
"resolved": "https://registry.npmjs.org/tinymce/-/tinymce-4.9.2.tgz",
"integrity": "sha512-ZRoTGG4GAsOI73QPSNkabO7nkoYw9H6cglRB44W2mMkxSiqxYi8WJlgkUphk0fDqo6ZD6r3E+NSP4UHxF2lySg=="
},
"tmp": {
"version": "0.0.33",

View File

@@ -39,7 +39,7 @@
"npm": "^6.4.1",
"signalr": "2.4.0",
"spectrum-colorpicker": "1.8.0",
"tinymce": "4.9.0",
"tinymce": "4.9.2",
"typeahead.js": "0.11.1",
"underscore": "1.9.1"
},

View File

@@ -30,7 +30,8 @@ angular.module("umbraco.directives")
promises.push(tinyMceService.getTinyMceEditorConfig({
htmlId: scope.uniqueId,
stylesheets: scope.configuration ? scope.configuration.stylesheets : null,
toolbar: toolbar
toolbar: toolbar,
mode: scope.configuration.mode
}));
// pin toolbar to top of screen if we have focus and it scrolls off the screen

View File

@@ -232,7 +232,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
body_class: 'umb-rte',
//see http://archive.tinymce.com/wiki.php/Configuration:cache_suffix
cache_suffix: "?umb__rnd=" + Umbraco.Sys.ServerVariables.application.cacheBuster
cache_suffix: "?umb__rnd=" + Umbraco.Sys.ServerVariables.application.cacheBuster,
//this is used to style the inline macro bits, sorry hard coding this form now since we don't have a standalone
//stylesheet to load in for this with only these styles (the color is @pinkLight)
content_style: ".mce-content-body .umb-macro-holder { border: 3px dotted #f5c1bc; padding: 7px; display: block; margin: 3px; } .umb-rte .mce-content-body .umb-macro-holder.loading {background: url(assets/img/loader.gif) right no-repeat; background-size: 18px; background-position-x: 99%;}"
};
if (tinyMceConfig.customConfig) {
@@ -458,7 +462,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
*/
createInsertMacro: function (editor, callback) {
var createInsertMacroScope = this;
let self = this;
let activeMacroElement = null; //track an active macro element
/** Adds custom rules for the macro plugin and custom serialization */
editor.on('preInit', function (args) {
@@ -474,6 +479,16 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
});
});
/** when the contents load we need to find any macros declared and load in their content */
editor.on("SetContent", function (o) {
//get all macro divs and load their content
$(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () {
self.loadMacroContent($(this), null);
});
});
/**
@@ -501,203 +516,26 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
tooltip: 'Insert macro',
onPostRender: function () {
var ctrl = this;
var isOnMacroElement = false;
let ctrl = this;
/**
if the selection comes from a different element that is not the macro's
we need to check if the selection includes part of the macro, if so we'll force the selection
to clear to the next element since if people can select part of the macro markup they can then modify it.
*/
function handleSelectionChange() {
if (!editor.selection.isCollapsed()) {
var endSelection = tinymce.activeEditor.selection.getEnd();
var startSelection = tinymce.activeEditor.selection.getStart();
//don't proceed if it's an entire element selected
if (endSelection !== startSelection) {
//if the end selection is a macro then move the cursor
//NOTE: we don't have to handle when the selection comes from a previous parent because
// that is automatically taken care of with the normal onNodeChanged logic since the
// evt.element will be the macro once it becomes part of the selection.
var $testForMacro = $(endSelection).closest(".umb-macro-holder");
if ($testForMacro.length > 0) {
//it came from before so move after, if there is no after then select ourselves
var next = $testForMacro.next();
if (next.length > 0) {
editor.selection.setCursorLocation($testForMacro.next().get(0));
} else {
selectMacroElement($testForMacro.get(0));
}
}
}
}
}
/** helper method to select the macro element */
function selectMacroElement(macroElement) {
// move selection to top element to ensure we can't edit this
editor.selection.select(macroElement);
// check if the current selection *is* the element (ie bug)
var currentSelection = editor.selection.getStart();
if (tinymce.isIE) {
if (!editor.dom.hasClass(currentSelection, 'umb-macro-holder')) {
while (!editor.dom.hasClass(currentSelection, 'umb-macro-holder') && currentSelection.parentNode) {
currentSelection = currentSelection.parentNode;
}
editor.selection.select(currentSelection);
}
}
}
/**
* Add a node change handler, test if we're editing a macro and select the whole thing, then set our isOnMacroElement flag.
* If we change the selection inside this method, then we end up in an infinite loop, so we have to remove ourselves
* from the event listener before changing selection, however, it seems that putting a break point in this method
* will always cause an 'infinite' loop as the caret keeps changing.
*
* TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/
* Check if the macro is currently selected and toggle the menu button
*/
function onNodeChanged(evt) {
//set our macro button active when on a node of class umb-macro-holder
var $macroElement = $(evt.element).closest(".umb-macro-holder");
handleSelectionChange();
//set the button active
ctrl.active($macroElement.length !== 0);
if ($macroElement.length > 0) {
var macroElement = $macroElement.get(0);
//remove the event listener before re-selecting
editor.off('NodeChange', onNodeChanged);
selectMacroElement(macroElement);
//set the flag
isOnMacroElement = true;
//re-add the event listener
editor.on('NodeChange', onNodeChanged);
} else {
isOnMacroElement = false;
}
activeMacroElement = getRealMacroElem(evt.element);
//set the button active/inactive
ctrl.active(activeMacroElement !== null);
}
/** when the contents load we need to find any macros declared and load in their content */
editor.on("LoadContent", function (o) {
//get all macro divs and load their content
$(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () {
createInsertMacroScope.loadMacroContent($(this), null);
});
});
/**
* This prevents any other commands from executing when the current element is the macro so the content cannot be edited
*
* TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/
*/
editor.on('BeforeExecCommand', function (o) {
if (isOnMacroElement) {
if (o.preventDefault) {
o.preventDefault();
}
if (o.stopImmediatePropagation) {
o.stopImmediatePropagation();
}
return;
}
});
/**
* This double checks and ensures you can't paste content into the rendered macro
*
* TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/
*/
editor.on("Paste", function (o) {
if (isOnMacroElement) {
if (o.preventDefault) {
o.preventDefault();
}
if (o.stopImmediatePropagation) {
o.stopImmediatePropagation();
}
return;
}
});
//NOTE: This could be another way to deal with the active/inactive state
//editor.on('ObjectSelected', function (e) {});
//set onNodeChanged event listener
editor.on('NodeChange', onNodeChanged);
/**
* Listen for the keydown in the editor, we'll check if we are currently on a macro element, if so
* we'll check if the key down is a supported key which requires an action, otherwise we ignore the request
* so the macro cannot be edited.
*
* TODO: I don't think we need this anymore with recent tinymce fixes: https://www.tiny.cloud/docs/plugins/noneditable/
*/
editor.on('KeyDown', function (e) {
if (isOnMacroElement) {
var macroElement = editor.selection.getNode();
//get the 'real' element (either p or the real one)
macroElement = getRealMacroElem(macroElement);
//prevent editing
e.preventDefault();
e.stopPropagation();
var moveSibling = function (element, isNext) {
var $e = $(element);
var $sibling = isNext ? $e.next() : $e.prev();
if ($sibling.length > 0) {
editor.selection.select($sibling.get(0));
editor.selection.collapse(true);
} else {
//if we're moving previous and there is no sibling, then lets recurse and just select the next one
if (!isNext) {
moveSibling(element, true);
return;
}
//if there is no sibling we'll generate a new p at the end and select it
editor.setContent(editor.getContent() + "<p>&nbsp;</p>");
editor.selection.select($(editor.dom.getRoot()).children().last().get(0));
editor.selection.collapse(true);
}
};
//supported keys to move to the next or prev element (13-enter, 27-esc, 38-up, 40-down, 39-right, 37-left)
//supported keys to remove the macro (8-backspace, 46-delete)
// TODO: Should we make the enter key insert a line break before or leave it as moving to the next element?
if ($.inArray(e.keyCode, [13, 40, 39]) !== -1) {
//move to next element
moveSibling(macroElement, true);
} else if ($.inArray(e.keyCode, [27, 38, 37]) !== -1) {
//move to prev element
moveSibling(macroElement, false);
} else if ($.inArray(e.keyCode, [8, 46]) !== -1) {
//delete macro element
//move first, then delete
moveSibling(macroElement, false);
editor.dom.remove(macroElement);
}
return;
}
});
},
/** The insert macro button click event handler */
@@ -710,11 +548,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
//when we click we could have a macro already selected and in that case we'll want to edit the current parameters
//so we'll need to extract them and submit them to the dialog.
var macroElement = editor.selection.getNode();
macroElement = getRealMacroElem(macroElement);
if (macroElement) {
if (activeMacroElement) {
//we have a macro selected so we'll need to parse it's alias and parameters
var contents = $(macroElement).contents();
var contents = $(activeMacroElement).contents();
var comment = _.find(contents, function (item) {
return item.nodeType === 8;
});
@@ -724,7 +560,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
var syntax = comment.textContent.trim();
var parsed = macroService.parseMacroSyntax(syntax);
dialogData = {
macroData: parsed
macroData: parsed,
activeMacroElement: activeMacroElement //pass the active element along so we can retrieve it later
};
}
@@ -737,7 +574,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
});
},
insertMacroInEditor: function (editor, macroObject) {
insertMacroInEditor: function (editor, macroObject, activeMacroElement) {
//Important note: the TinyMce plugin "noneditable" is used here so that the macro cannot be edited,
// for this to work the mceNonEditable class needs to come last and we also need to use the attribute contenteditable = false
// (even though all the docs and examples say that is not necessary)
//put the macro syntax in comments, we will parse this out on the server side to be used
//for persisting.
@@ -746,11 +587,18 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
var uniqueId = "umb-macro-" + editor.dom.uniqueId();
var macroDiv = editor.dom.create('div',
{
'class': 'umb-macro-holder ' + macroObject.macroAlias + ' mceNonEditable ' + uniqueId
'class': 'umb-macro-holder ' + macroObject.macroAlias + " " + uniqueId + ' mceNonEditable',
'contenteditable': 'false'
},
macroSyntaxComment + '<ins>Macro alias: <strong>' + macroObject.macroAlias + '</strong></ins>');
editor.selection.setNode(macroDiv);
//if there's an activeMacroElement then replace it, otherwise set the contents of the selected node
if (activeMacroElement) {
activeMacroElement.replaceWith(macroDiv); //directly replaces the html node
}
else {
editor.selection.setNode(macroDiv);
}
var $macroDiv = $(editor.dom.select("div.umb-macro-holder." + uniqueId));
@@ -1167,10 +1015,15 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
pinToolbar : function (editor) {
//we can't pin the toolbar if this doesn't exist (i.e. when in distraction free mode)
if (!editor.editorContainer) {
return;
}
var tinyMce = $(editor.editorContainer);
var toolbar = tinyMce.find(".mce-toolbar");
var toolbarHeight = toolbar.height();
var tinyMceRect = tinyMce[0].getBoundingClientRect();
var tinyMceRect = editor.editorContainer.getBoundingClientRect();
var tinyMceTop = tinyMceRect.top;
var tinyMceBottom = tinyMceRect.bottom;
var tinyMceWidth = tinyMceRect.width;
@@ -1288,7 +1141,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
}
});
var self = this;
let self = this;
//create link picker
self.createLinkPicker(args.editor, function (currentTarget, anchorElement) {
@@ -1346,7 +1199,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
dialogData: dialogData,
submit: function (model) {
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, dialogData.renderingEngine);
self.insertMacroInEditor(args.editor, macroObject);
self.insertMacroInEditor(args.editor, macroObject, dialogData.activeMacroElement);
editorService.close();
},
close: function () {

View File

@@ -25,13 +25,6 @@
padding:10px;
}
/* loader for macro loading in tinymce*/
.umb-rte .mce-content-body .umb-macro-holder.loading {
background: url(img/loader.gif) right no-repeat;
background-size: 18px;
background-position-x: 99%;
}
.umb-rte .mce-container {
box-sizing: border-box;
}

View File

@@ -94,6 +94,9 @@ namespace Umbraco.Web.Composing
public static UmbracoContext UmbracoContext
=> UmbracoContextAccessor.UmbracoContext;
public static UmbracoHelper UmbracoHelper
=> Factory.GetInstance<UmbracoHelper>();
public static DistributedCache DistributedCache
=> Factory.GetInstance<DistributedCache>();

View File

@@ -20,18 +20,13 @@ namespace Umbraco.Web.Controllers
// TODO: This controller should be moved to a more suitable place.
public class TagsController : UmbracoApiController
{
/// <summary>
/// Initializes a new instance of the <see cref="TagsController"/> with auto dependencies.
/// </summary>
public TagsController()
{ }
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TagsController"/> with all its dependencies.
/// </summary>
public TagsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{ }
public TagsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Get every tag stored in the database (with optional group)

View File

@@ -12,11 +12,12 @@ namespace Umbraco.Web.Controllers
public class UmbLoginController : SurfaceController
{
public UmbLoginController()
{ }
{
}
public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger)
{ }
public UmbLoginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper)
{
}
[HttpPost]
[ValidateAntiForgeryToken]

View File

@@ -14,11 +14,12 @@ namespace Umbraco.Web.Controllers
public class UmbLoginStatusController : SurfaceController
{
public UmbLoginStatusController()
{ }
{
}
public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger)
{ }
public UmbLoginStatusController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper)
{
}
[HttpPost]
[ValidateAntiForgeryToken]

View File

@@ -17,8 +17,8 @@ namespace Umbraco.Web.Controllers
public UmbProfileController()
{ }
public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger)
public UmbProfileController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper)
{ }
[HttpPost]

View File

@@ -14,11 +14,12 @@ namespace Umbraco.Web.Controllers
public class UmbRegisterController : SurfaceController
{
public UmbRegisterController()
{ }
{
}
public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger)
{ }
public UmbRegisterController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper) : base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper)
{
}
[HttpPost]
[ValidateAntiForgeryToken]

View File

@@ -43,18 +43,9 @@ namespace Umbraco.Web.Editors
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
private BackOfficeSignInManager _signInManager;
/// <summary>
/// Initializes a new instance of the new <see cref="AuthenticationController"/> class with auto dependencies.
/// </summary>
public AuthenticationController()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="AuthenticationController"/> class with all its dependencies.
/// </summary>
public AuthenticationController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{ }
public AuthenticationController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager => _userManager
?? (_userManager = TryGetOwinContext().Result.GetBackOfficeUserManager());

View File

@@ -49,8 +49,8 @@ namespace Umbraco.Web.Editors
private const string TokenPasswordResetCode = "PasswordResetCode";
private static readonly string[] TempDataTokenNames = { TokenExternalSignInError, TokenPasswordResetCode };
public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger)
public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper)
{
_manifestParser = manifestParser;
_features = features;

View File

@@ -1,4 +1,10 @@
using Umbraco.Web.WebApi;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.WebApi;
using Umbraco.Web.WebApi.Filters;
namespace Umbraco.Web.Editors
@@ -11,5 +17,9 @@ namespace Umbraco.Web.Editors
[AppendCurrentEventMessages]
[PrefixlessBodyModelValidator]
public abstract class BackOfficeNotificationsController : UmbracoAuthorizedJsonController
{ }
{
protected BackOfficeNotificationsController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
}
}

View File

@@ -8,8 +8,12 @@ using System.Net.Http;
using System.Web.Http;
using ClientDependency.Core;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Core.Strings.Css;
using Umbraco.Web.Composing;
@@ -30,6 +34,9 @@ namespace Umbraco.Web.Editors
[UmbracoApplicationAuthorize(Core.Constants.Applications.Settings)]
public class CodeFileController : BackOfficeNotificationsController
{
public CodeFileController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Used to create a brand new file

View File

@@ -11,6 +11,8 @@ using System.Web.Http.ModelBinding;
using System.Web.Security;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
@@ -33,6 +35,7 @@ using Umbraco.Web.ContentApps;
using Umbraco.Web.Editors.Binders;
using Umbraco.Web.Editors.Filters;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence;
using Umbraco.Core.Security;
namespace Umbraco.Web.Editors
@@ -54,7 +57,7 @@ namespace Umbraco.Web.Editors
public object Domains { get; private set; }
public ContentController(PropertyEditorCollection propertyEditors)
public ContentController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
_allLangs = new Lazy<IDictionary<string, ILanguage>>(() => Services.LocalizationService.GetAllLanguages().ToDictionary(x => x.IsoCode, x => x, StringComparer.InvariantCultureIgnoreCase));

View File

@@ -4,9 +4,12 @@ using System.Net;
using System.Net.Http;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
@@ -23,6 +26,10 @@ namespace Umbraco.Web.Editors
[JsonDateTimeFormatAttribute]
public abstract class ContentControllerBase : BackOfficeNotificationsController
{
protected ContentControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
protected HttpResponseMessage HandleContentNotFound(object id, bool throwException = true)
{
ModelState.AddModelError("id", $"content with id: {id} was not found");

View File

@@ -54,8 +54,8 @@ namespace Umbraco.Web.Editors
UmbracoContext umbracoContext,
ISqlContext sqlContext, PropertyEditorCollection propertyEditors,
ServiceContext services, AppCaches appCaches,
IProfilingLogger logger, IRuntimeState runtimeState)
: base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_serializer = serializer;
_propertyEditors = propertyEditors;

View File

@@ -33,8 +33,8 @@ namespace Umbraco.Web.Editors
private readonly ICultureDictionaryFactory _cultureDictionaryFactory;
private ICultureDictionary _cultureDictionary;
protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
protected ContentTypeControllerBase(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_cultureDictionaryFactory = cultureDictionaryFactory;
}

View File

@@ -31,18 +31,12 @@ namespace Umbraco.Web.Editors
public class DashboardController : UmbracoApiController
{
private readonly IDashboardService _dashboardService;
/// <summary>
/// Initializes a new instance of the <see cref="DashboardController"/> with auto dependencies.
/// </summary>
public DashboardController()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="DashboardController"/> with all its dependencies.
/// </summary>
public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
public DashboardController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, IDashboardService dashboardService, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_dashboardService = dashboardService;
}

View File

@@ -16,8 +16,11 @@ using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using System.Net.Http;
using System.Text;
using Umbraco.Core.Cache;
using Umbraco.Web.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
namespace Umbraco.Web.Editors
{
@@ -36,7 +39,7 @@ namespace Umbraco.Web.Editors
{
private readonly PropertyEditorCollection _propertyEditors;
public DataTypeController(PropertyEditorCollection propertyEditors)
public DataTypeController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_propertyEditors = propertyEditors;
}

View File

@@ -5,7 +5,13 @@ using System.Net;
using System.Net.Http;
using System.Web.Http;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -28,6 +34,10 @@ namespace Umbraco.Web.Editors
[EnableOverrideAuthorization]
public class DictionaryController : BackOfficeNotificationsController
{
public DictionaryController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Deletes a data type with a given ID
/// </summary>

View File

@@ -47,8 +47,8 @@ namespace Umbraco.Web.Editors
private readonly SearchableTreeCollection _searchableTreeCollection;
public EntityController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState,
ITreeService treeService, SearchableTreeCollection searchableTreeCollection, UmbracoTreeSearcher treeSearcher)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
ITreeService treeService, UmbracoHelper umbracoHelper, SearchableTreeCollection searchableTreeCollection, UmbracoTreeSearcher treeSearcher)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_treeService = treeService;
_searchableTreeCollection = searchableTreeCollection;
@@ -108,6 +108,8 @@ namespace Umbraco.Web.Editors
if (string.IsNullOrEmpty(query))
return Enumerable.Empty<EntityBasic>();
//TODO: This uses the internal UmbracoTreeSearcher, this instead should delgate to the ISearchableTree implementation for the type
return ExamineSearch(query, type, searchFrom);
}
@@ -451,6 +453,9 @@ namespace Umbraco.Web.Editors
//the EntityService cannot search members of a certain type, this is currently not supported and would require
//quite a bit of plumbing to do in the Services/Repository, we'll revert to a paged search
//TODO: We should really fix this in the EntityService but if we don't we should allow the ISearchableTree for the members controller
// to be used for this search instead of the built in/internal searcher
var searchResult = _treeSearcher.ExamineSearch(filter ?? "", type, pageSize, pageNumber - 1, out long total, id);
return new PagedResult<EntityBasic>(total, pageNumber, pageSize)

View File

@@ -32,9 +32,12 @@ namespace Umbraco.Web.Editors
{
private readonly IMacroService _macroService;
private readonly IContentService _contentService;
private readonly IUmbracoComponentRenderer _componentRenderer;
private readonly IVariationContextAccessor _variationContextAccessor;
public MacroRenderingController(IVariationContextAccessor variationContextAccessor, IMacroService macroService, IContentService contentService)
public MacroRenderingController(IUmbracoComponentRenderer componentRenderer, IVariationContextAccessor variationContextAccessor, IMacroService macroService, IContentService contentService)
{
_componentRenderer = componentRenderer;
_variationContextAccessor = variationContextAccessor;
_macroService = macroService;
_contentService = contentService;
@@ -99,21 +102,15 @@ namespace Umbraco.Web.Editors
private HttpResponseMessage GetMacroResultAsHtml(string macroAlias, int pageId, IDictionary<string, object> macroParams)
{
// note - here we should be using the cache, provided that the preview content is in the cache...
var doc = _contentService.GetById(pageId);
if (doc == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
var m = _macroService.GetByAlias(macroAlias);
if (m == null)
throw new HttpResponseException(HttpStatusCode.NotFound);
var macro = new MacroModel(m);
var publishedContent = UmbracoContext.ContentCache.GetById(true, pageId);
//if it isn't supposed to be rendered in the editor then return an empty string
if (macro.RenderInEditor == false)
//currently we cannot render a macro if the page doesn't yet exist
if (pageId == -1 || publishedContent == null || !m.UseInEditor)
{
var response = Request.CreateResponse();
//need to create a specific content result formatted as HTML since this controller has been configured
@@ -123,32 +120,24 @@ namespace Umbraco.Web.Editors
return response;
}
//because macro's are filled with insane legacy bits and pieces we need all sorts of weirdness to make them render.
//the 'easiest' way might be to create an IPublishedContent manually and populate the legacy 'page' object with that
//and then set the legacy parameters.
// When rendering the macro in the backoffice the default setting would be to use the Culture of the logged in user.
// Since a Macro might contain thing thats related to the culture of the "IPublishedContent" (ie Dictionary keys) we want
// to set the current culture to the culture related to the content item. This is hacky but it works.
var publishedContent = UmbracoContext.ContentCache.GetById(doc.Id);
var culture = publishedContent?.GetCulture();
var culture = publishedContent.GetCulture();
_variationContextAccessor.VariationContext = new VariationContext(); //must have an active variation context!
if (culture != null)
{
Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture.Culture);
_variationContextAccessor.VariationContext = new VariationContext(Thread.CurrentThread.CurrentCulture.Name);
}
var legacyPage = new global::Umbraco.Web.Macros.PublishedContentHashtableConverter(doc, _variationContextAccessor);
UmbracoContext.HttpContext.Items["pageElements"] = legacyPage.Elements;
UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null;
var renderer = new UmbracoComponentRenderer(UmbracoContext);
var result = Request.CreateResponse();
//need to create a specific content result formatted as HTML since this controller has been configured
//with only json formatters.
result.Content = new StringContent(
renderer.RenderMacro(macro, macroParams, legacyPage).ToString(),
_componentRenderer.RenderMacro(pageId, m.Alias, macroParams).ToString(),
Encoding.UTF8,
"text/html");
return result;

View File

@@ -7,9 +7,12 @@ using System.Net;
using System.Net.Http;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Web.Composing;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
@@ -29,9 +32,9 @@ namespace Umbraco.Web.Editors
{
private readonly IMacroService _macroService;
public MacrosController(IMacroService macroService)
public MacrosController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_macroService = macroService;
_macroService = Services.MacroService;
}
/// <summary>

View File

@@ -21,7 +21,9 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
using System.Linq;
using System.Web.Http.Controllers;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using Umbraco.Core.Persistence.Querying;
@@ -47,7 +49,7 @@ namespace Umbraco.Web.Editors
[MediaControllerControllerConfiguration]
public class MediaController : ContentControllerBase
{
public MediaController(PropertyEditorCollection propertyEditors, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider)
public MediaController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;

View File

@@ -37,8 +37,7 @@ namespace Umbraco.Web.Editors
[MediaTypeControllerControllerConfiguration]
public class MediaTypeController : ContentTypeControllerBase<IMediaType>
{
public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
public MediaTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}

View File

@@ -26,7 +26,10 @@ using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
using Constants = Umbraco.Core.Constants;
using System.Collections.Generic;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.ContentApps;
using Umbraco.Web.Editors.Binders;
@@ -43,7 +46,7 @@ namespace Umbraco.Web.Editors
[OutgoingNoHyphenGuidFormat]
public class MemberController : ContentControllerBase
{
public MemberController(PropertyEditorCollection propertyEditors)
public MemberController(PropertyEditorCollection propertyEditors, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_propertyEditors = propertyEditors ?? throw new ArgumentNullException(nameof(propertyEditors));
}

View File

@@ -30,8 +30,7 @@ namespace Umbraco.Web.Editors
[UmbracoTreeAuthorize(new string[] { Constants.Trees.MemberTypes, Constants.Trees.Members})]
public class MemberTypeController : ContentTypeControllerBase<IMemberType>
{
public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
public MemberTypeController(ICultureDictionaryFactory cultureDictionaryFactory, IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(cultureDictionaryFactory, globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}

View File

@@ -36,8 +36,8 @@ namespace Umbraco.Web.Editors
{
public PackageInstallController(IGlobalSettings globalSettings, UmbracoContext umbracoContext,
ISqlContext sqlContext, ServiceContext services, AppCaches appCaches,
IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}

View File

@@ -35,7 +35,7 @@ namespace Umbraco.Web.Editors
public IHttpActionResult GetEnableState()
{
var enabled = Current.Configs.Settings().WebRouting.DisableRedirectUrlTracking == false;
var userIsAdmin = Umbraco.UmbracoContext.Security.CurrentUser.IsAdmin();
var userIsAdmin = UmbracoContext.Security.CurrentUser.IsAdmin();
return Ok(new { enabled, userIsAdmin });
}
@@ -92,7 +92,7 @@ namespace Umbraco.Web.Editors
[HttpPost]
public IHttpActionResult ToggleUrlTracker(bool disable)
{
var userIsAdmin = Umbraco.UmbracoContext.Security.CurrentUser.IsAdmin();
var userIsAdmin = UmbracoContext.Security.CurrentUser.IsAdmin();
if (userIsAdmin == false)
{
var errorMessage = "User is not a member of the administrators group and so is not allowed to toggle the URL tracker";

View File

@@ -5,7 +5,12 @@ using System.Net.Http;
using System.Web.Http;
using AutoMapper;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi;
@@ -22,6 +27,10 @@ namespace Umbraco.Web.Editors
[EnableOverrideAuthorization]
public class RelationTypeController : BackOfficeNotificationsController
{
public RelationTypeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Gets a relation type by ID.
/// </summary>

View File

@@ -27,8 +27,8 @@ namespace Umbraco.Web.Editors
private readonly ITreeService _treeService;
public SectionController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState,
IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
IDashboardService dashboardService, ISectionService sectionService, ITreeService treeService, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_dashboardService = dashboardService;
_sectionService = sectionService;
@@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors
// this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that
// since tree's by nature are controllers and require request contextual data
var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService)
var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, Umbraco)
{
ControllerContext = ControllerContext
};

View File

@@ -4,8 +4,14 @@ using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Filters;
@@ -17,6 +23,10 @@ namespace Umbraco.Web.Editors
[UmbracoTreeAuthorize(Constants.Trees.Templates)]
public class TemplateController : BackOfficeNotificationsController
{
public TemplateController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Gets data type by alias
/// </summary>

View File

@@ -20,24 +20,11 @@ namespace Umbraco.Web.Editors
[AngularJsonOnlyConfiguration]
public abstract class UmbracoAuthorizedJsonController : UmbracoAuthorizedApiController
{
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoAuthorizedJsonController"/> with auto dependencies.
/// </summary>
protected UmbracoAuthorizedJsonController()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoAuthorizedJsonController"/> class with all its dependencies.
/// </summary>
/// <param name="globalSettings"></param>
/// <param name="umbracoContext"></param>
/// <param name="sqlContext"></param>
/// <param name="services"></param>
/// <param name="appCaches"></param>
/// <param name="logger"></param>
/// <param name="runtimeState"></param>
protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
protected UmbracoAuthorizedJsonController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
}

View File

@@ -17,10 +17,12 @@ using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Editors;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Security;
@@ -43,6 +45,10 @@ namespace Umbraco.Web.Editors
[IsCurrentUserModelFilter]
public class UsersController : UmbracoAuthorizedJsonController
{
public UsersController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Returns a list of the sizes of gravatar urls for the user or null if the gravatar server cannot be reached
/// </summary>

View File

@@ -92,13 +92,13 @@ namespace Umbraco.Web
{
throw new InvalidOperationException("Cannot cache by page if the UmbracoContext has not been initialized, this parameter can only be used in the context of an Umbraco request");
}
cacheKey.AppendFormat("{0}-", UmbracoContext.Current.PageId);
cacheKey.AppendFormat("{0}-", UmbracoContext.Current.PublishedRequest?.PublishedContent?.Id ?? 0);
}
if (cacheByMember)
{
var helper = Current.Factory.GetInstance<MembershipHelper>();
var currentMember = helper.GetCurrentMember();
cacheKey.AppendFormat("m{0}-", currentMember == null ? 0 : currentMember.Id);
cacheKey.AppendFormat("m{0}-", currentMember?.Id ?? 0);
}
if (contextualKeyBuilder != null)
{

View File

@@ -12,32 +12,35 @@ namespace Umbraco.Web
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="pageId"></param>
/// <param name="contentId"></param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
IHtmlString RenderTemplate(int pageId, int? altTemplateId = null);
IHtmlString RenderTemplate(int contentId, int? altTemplateId = null);
/// <summary>
/// Renders the macro with the specified alias.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <returns></returns>
IHtmlString RenderMacro(string alias);
IHtmlString RenderMacro(int contentId, string alias);
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
IHtmlString RenderMacro(string alias, object parameters);
IHtmlString RenderMacro(int contentId, string alias, object parameters);
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
IHtmlString RenderMacro(string alias, IDictionary<string, object> parameters);
IHtmlString RenderMacro(int contentId, string alias, IDictionary<string, object> parameters);
}
}

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Macros
{
/// <summary>
/// Renders a macro
/// </summary>
public interface IMacroRenderer
{
MacroContent Render(string macroAlias, IPublishedContent content, IDictionary<string, object> macroParams);
}
}

View File

@@ -1,22 +1,25 @@
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Umbraco.Core;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Services.Implement;
namespace Umbraco.Web.Macros
{
public class MacroModel
{
/// <summary>
/// The Macro Id
/// </summary>
public int Id { get; set; }
/// <summary>
/// The Macro Name
/// </summary>
public string Name { get; set; }
/// <summary>
/// The Macro Alias
/// </summary>
public string Alias { get; set; }
public string MacroControlIdentifier { get; set; }
public MacroTypes MacroType { get; set; }
public string MacroSource { get; set; }

View File

@@ -3,45 +3,44 @@ using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Caching;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Events;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Macros;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
namespace Umbraco.Web.Macros
{
public class MacroRenderer
internal class MacroRenderer : IMacroRenderer
{
private readonly IProfilingLogger _plogger;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IContentSection _contentSection;
private readonly ILocalizedTextService _textService;
private readonly AppCaches _appCaches;
private readonly IMacroService _macroService;
// TODO: there are many more things that would need to be injected in here
public MacroRenderer(IProfilingLogger plogger)
public MacroRenderer(IProfilingLogger plogger, IUmbracoContextAccessor umbracoContextAccessor, IContentSection contentSection, ILocalizedTextService textService, AppCaches appCaches, IMacroService macroService)
{
_plogger = plogger;
_plogger = plogger ?? throw new ArgumentNullException(nameof(plogger));
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_contentSection = contentSection ?? throw new ArgumentNullException(nameof(contentSection));
_textService = textService;
_appCaches = appCaches ?? throw new ArgumentNullException(nameof(appCaches));
_macroService = macroService ?? throw new ArgumentNullException(nameof(macroService));
}
// probably can do better - just porting from v7
public IList<Exception> Exceptions { get; } = new List<Exception>();
#region MacroContent cache
// gets this macro content cache identifier
private static string GetContentCacheIdentifier(MacroModel model, int pageId)
private string GetContentCacheIdentifier(MacroModel model, int pageId)
{
var id = new StringBuilder();
@@ -55,8 +54,9 @@ namespace Umbraco.Web.Macros
{
object key = 0;
if (HttpContext.Current.User.Identity.IsAuthenticated)
if (_umbracoContextAccessor.UmbracoContext.HttpContext?.User?.Identity?.IsAuthenticated ?? false)
{
//ugh, membershipproviders :(
var provider = Core.Security.MembershipProviderExtensions.GetMembersMembershipProvider();
var member = Core.Security.MembershipProviderExtensions.GetCurrentUser(provider);
key = member?.ProviderUserKey ?? 0;
@@ -71,34 +71,19 @@ namespace Umbraco.Web.Macros
return id.ToString();
}
private static string GenerateCacheKeyFromCode(string input)
{
if (string.IsNullOrEmpty(input)) throw new ArgumentNullException(nameof(input));
// step 1, calculate MD5 hash from input
var md5 = MD5.Create();
var inputBytes = Encoding.ASCII.GetBytes(input);
var hash = md5.ComputeHash(inputBytes);
// step 2, convert byte array to hex string
var sb = new StringBuilder();
foreach (var h in hash) sb.Append(h.ToString("X2"));
return sb.ToString();
}
// gets this macro content from the cache
// ensuring that it is appropriate to use the cache
private static MacroContent GetMacroContentFromCache(MacroModel model)
private MacroContent GetMacroContentFromCache(MacroModel model)
{
// only if cache is enabled
if (UmbracoContext.Current.InPreviewMode || model.CacheDuration <= 0) return null;
if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return null;
var cache = Current.AppCaches.RuntimeCache;
var cache = _appCaches.RuntimeCache;
var macroContent = cache.GetCacheItem<MacroContent>(CacheKeys.MacroContentCacheKey + model.CacheIdentifier);
if (macroContent == null) return null;
Current.Logger.Debug<MacroRenderer>("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier);
_plogger.Debug<MacroRenderer>("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier);
// ensure that the source has not changed
// note: does not handle dependencies, and never has
@@ -107,13 +92,13 @@ namespace Umbraco.Web.Macros
{
if (macroSource.Exists == false)
{
Current.Logger.Debug<MacroRenderer>("Macro source does not exist anymore, ignore cache.");
_plogger.Debug<MacroRenderer>("Macro source does not exist anymore, ignore cache.");
return null;
}
if (macroContent.Date < macroSource.LastWriteTime)
{
Current.Logger.Debug<MacroRenderer>("Macro source has changed, ignore cache.");
_plogger.Debug<MacroRenderer>("Macro source has changed, ignore cache.");
return null;
}
}
@@ -126,10 +111,10 @@ namespace Umbraco.Web.Macros
}
// stores macro content into the cache
private static void AddMacroContentToCache(MacroModel model, MacroContent macroContent)
private void AddMacroContentToCache(MacroModel model, MacroContent macroContent)
{
// only if cache is enabled
if (UmbracoContext.Current.InPreviewMode || model.CacheDuration <= 0) return;
if (_umbracoContextAccessor.UmbracoContext.InPreviewMode || model.CacheDuration <= 0) return;
// just make sure...
if (macroContent == null) return;
@@ -150,7 +135,7 @@ namespace Umbraco.Web.Macros
// remember when we cache the content
macroContent.Date = DateTime.Now;
var cache = Current.AppCaches.RuntimeCache;
var cache = _appCaches.RuntimeCache;
cache.Insert(
CacheKeys.MacroContentCacheKey + model.CacheIdentifier,
() => macroContent,
@@ -158,7 +143,7 @@ namespace Umbraco.Web.Macros
priority: CacheItemPriority.NotRemovable
);
Current.Logger.Debug<MacroRenderer>("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier);
_plogger.Debug<MacroRenderer>("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier);
}
// gets the macro source file name
@@ -183,7 +168,7 @@ namespace Umbraco.Web.Macros
// gets the macro source file
// null if macro is not file-based
internal static FileInfo GetMacroFile(MacroModel model)
private static FileInfo GetMacroFile(MacroModel model)
{
var filename = GetMacroFileName(model);
if (filename == null) return null;
@@ -195,47 +180,38 @@ namespace Umbraco.Web.Macros
return file.Exists ? file : null;
}
#endregion
#region MacroModel properties
// updates the model properties values according to the attributes
private static void UpdateMacroModelProperties(MacroModel model, Hashtable attributes)
private static void UpdateMacroModelProperties(MacroModel model, IDictionary<string, object> macroParams)
{
foreach (var prop in model.Properties)
{
var key = prop.Key.ToLowerInvariant();
prop.Value = attributes.ContainsKey(key)
? attributes[key]?.ToString() ?? string.Empty
prop.Value = macroParams.ContainsKey(key)
? macroParams[key]?.ToString() ?? string.Empty
: string.Empty;
}
}
// generates the model properties according to the attributes
public static void GenerateMacroModelPropertiesFromAttributes(MacroModel model, Hashtable attributes)
{
foreach (string key in attributes.Keys)
model.Properties.Add(new MacroPropertyModel(key, attributes[key].ToString()));
}
}
#endregion
#region Render/Execute
// still, this is ugly. The macro should have a Content property
// referring to IPublishedContent we're rendering the macro against,
// this is all so convoluted ;-(
public MacroContent Render(MacroModel macro, Hashtable pageElements, int pageId, Hashtable attributes)
public MacroContent Render(string macroAlias, IPublishedContent content, IDictionary<string, object> macroParams)
{
UpdateMacroModelProperties(macro, attributes);
return Render(macro, pageElements, pageId);
var m = _macroService.GetByAlias(macroAlias);
if (m == null)
throw new InvalidOperationException("No macro found by alias " + macroAlias);
var page = new PublishedContentHashtableConverter(content);
var macro = new MacroModel(m);
UpdateMacroModelProperties(macro, macroParams);
return Render(macro, content, page.Elements);
}
public MacroContent Render(MacroModel macro, Hashtable pageElements, int pageId)
private MacroContent Render(MacroModel macro, IPublishedContent content, IDictionary pageElements)
{
// trigger MacroRendering event so that the model can be manipulated before rendering
OnMacroRendering(new MacroRenderingEventArgs(pageElements, pageId));
if (content == null) throw new ArgumentNullException(nameof(content));
var macroInfo = $"Render Macro: {macro.Name}, type: {macro.MacroType}, cache: {macro.CacheDuration}";
using (_plogger.DebugDuration<MacroRenderer>(macroInfo, "Rendered Macro."))
@@ -244,7 +220,7 @@ namespace Umbraco.Web.Macros
foreach (var prop in macro.Properties)
prop.Value = ParseAttribute(pageElements, prop.Value);
macro.CacheIdentifier = GetContentCacheIdentifier(macro, pageId);
macro.CacheIdentifier = GetContentCacheIdentifier(macro, content.Id);
// get the macro from cache if it is there
var macroContent = GetMacroContentFromCache(macro);
@@ -258,7 +234,7 @@ namespace Umbraco.Web.Macros
// this will take care of errors
// it may throw, if we actually want to throw, so better not
// catch anything here and let the exception be thrown
var attempt = ExecuteMacroOfType(macro);
var attempt = ExecuteMacroOfType(macro, content);
// by convention ExecuteMacroByType must either throw or return a result
// just check to avoid internal errors
@@ -300,8 +276,6 @@ namespace Umbraco.Web.Macros
}
catch (Exception e)
{
Exceptions.Add(e);
_plogger.Warn<MacroRenderer>(e, "Failed {MsgIn}", msgIn);
var macroErrorEventArgs = new MacroErrorEventArgs
@@ -310,11 +284,9 @@ namespace Umbraco.Web.Macros
Alias = macro.Alias,
MacroSource = macro.MacroSource,
Exception = e,
Behaviour = Current.Configs.Settings().Content.MacroErrorBehaviour
Behaviour = _contentSection.MacroErrorBehaviour
};
OnError(macroErrorEventArgs);
switch (macroErrorEventArgs.Behaviour)
{
case MacroErrorBehaviour.Inline:
@@ -341,16 +313,17 @@ namespace Umbraco.Web.Macros
/// <remarks>Returns an attempt that is successful if the macro ran successfully. If the macro failed
/// to run properly, the attempt fails, though it may contain a content. But for instance that content
/// should not be cached. In that case the attempt may also contain an exception.</remarks>
private Attempt<MacroContent> ExecuteMacroOfType(MacroModel model)
private Attempt<MacroContent> ExecuteMacroOfType(MacroModel model, IPublishedContent content)
{
if (model == null) throw new ArgumentNullException(nameof(model));
// ensure that we are running against a published node (ie available in XML)
// that may not be the case if the macro is embedded in a RTE of an unpublished document
if (UmbracoContext.Current.PublishedRequest == null
|| UmbracoContext.Current.PublishedRequest.HasPublishedContent == false)
return Attempt.Fail(new MacroContent { Text = "[macro]" });
if (content == null)
return Attempt.Fail(new MacroContent { Text = "[macro failed (no content)]" });
var textService = Current.Services.TextService;
var textService = _textService;
switch (model.MacroType)
{
@@ -358,7 +331,7 @@ namespace Umbraco.Web.Macros
return ExecuteMacroWithErrorWrapper(model,
$"Executing PartialView: MacroSource=\"{model.MacroSource}\".",
"Executed PartialView.",
() => ExecutePartialView(model),
() => ExecutePartialView(model, content),
() => textService.Localize("errors/macroErrorLoadingPartialView", new[] { model.MacroSource }));
default:
@@ -370,21 +343,6 @@ namespace Umbraco.Web.Macros
}
}
// raised when a macro triggers an error
public static event TypedEventHandler<MacroRenderer, MacroErrorEventArgs> Error;
protected void OnError(MacroErrorEventArgs e)
{
Error?.Invoke(this, e);
}
// raised before the macro renders, allowing devs to modify it
public static event TypedEventHandler<MacroRenderer, MacroRenderingEventArgs> MacroRendering;
protected void OnMacroRendering(MacroRenderingEventArgs e)
{
MacroRendering?.Invoke(this, e);
}
#endregion
@@ -394,10 +352,9 @@ namespace Umbraco.Web.Macros
/// Renders a PartialView Macro.
/// </summary>
/// <returns>The text output of the macro execution.</returns>
private static MacroContent ExecutePartialView(MacroModel macro)
private MacroContent ExecutePartialView(MacroModel macro, IPublishedContent content)
{
var engine = new PartialViewMacroEngine();
var content = UmbracoContext.Current.PublishedRequest.PublishedContent;
return engine.Execute(macro, content);
}
@@ -407,8 +364,9 @@ namespace Umbraco.Web.Macros
// parses attribute value looking for [@requestKey], [%sessionKey], [#pageElement], [$recursiveValue]
// supports fallbacks eg "[@requestKey],[%sessionKey],1234"
public static string ParseAttribute(IDictionary pageElements, string attributeValue)
private string ParseAttribute(IDictionary pageElements, string attributeValue)
{
if (pageElements == null) throw new ArgumentNullException(nameof(pageElements));
// check for potential querystring/cookie variables
attributeValue = attributeValue.Trim();
@@ -431,7 +389,7 @@ namespace Umbraco.Web.Macros
return attributeValue;
}
var context = HttpContext.Current;
var context = _umbracoContextAccessor.UmbracoContext.HttpContext;
foreach (var token in tokens)
{
@@ -458,11 +416,9 @@ namespace Umbraco.Web.Macros
attributeValue = context?.Request.GetCookieValue(name);
break;
case '#':
if (pageElements == null) pageElements = GetPageElements();
attributeValue = pageElements[name]?.ToString();
break;
case '$':
if (pageElements == null) pageElements = GetPageElements();
attributeValue = pageElements[name]?.ToString();
if (string.IsNullOrEmpty(attributeValue))
attributeValue = ParseAttributeOnParents(pageElements, name);
@@ -477,12 +433,13 @@ namespace Umbraco.Web.Macros
return attributeValue;
}
private static string ParseAttributeOnParents(IDictionary pageElements, string name)
private string ParseAttributeOnParents(IDictionary pageElements, string name)
{
if (pageElements == null) throw new ArgumentNullException(nameof(pageElements));
// this was, and still is, an ugly piece of nonsense
var value = string.Empty;
var cache = UmbracoContext.Current.ContentCache; // should be injected
var cache = _umbracoContextAccessor.UmbracoContext.ContentCache;
var splitpath = (string[])pageElements["splitpath"];
for (var i = splitpath.Length - 1; i > 0; i--) // at 0 we have root (-1)
@@ -495,195 +452,9 @@ namespace Umbraco.Web.Macros
return value;
}
private static IDictionary GetPageElements()
{
IDictionary pageElements = null;
if (HttpContext.Current.Items["pageElements"] != null)
pageElements = (IDictionary)HttpContext.Current.Items["pageElements"];
return pageElements;
}
#endregion
#region RTE macros
public static string RenderMacroStartTag(Hashtable attributes, int pageId, Guid versionId)
{
var div = "<div ";
var ide = attributes.GetEnumerator();
while (ide.MoveNext())
{
div += $"umb_{ide.Key}=\"{EncodeMacroAttribute((ide.Value ?? String.Empty).ToString())}\" ";
}
div += $"ismacro=\"true\" onresizestart=\"return false;\" umbVersionId=\"{versionId}\" umbPageid=\"{pageId}\""
+ " title=\"This is rendered content from macro\" class=\"umbMacroHolder\"><!-- startUmbMacro -->";
return div;
}
private static string EncodeMacroAttribute(string attributeContents)
{
// replace line breaks
attributeContents = attributeContents.Replace("\n", "\\n").Replace("\r", "\\r");
// replace quotes
attributeContents = attributeContents.Replace("\"", "&quot;");
// replace tag start/ends
attributeContents = attributeContents.Replace("<", "&lt;").Replace(">", "&gt;");
return attributeContents;
}
public static string RenderMacroEndTag()
{
return "<!-- endUmbMacro --></div>";
}
private static readonly Regex HrefRegex = new Regex("href=\"([^\"]*)\"",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
public static string GetRenderedMacro(int macroId, Hashtable elements, Hashtable attributes, int pageId, IMacroService macroService, IProfilingLogger plogger)
{
var m = macroService.GetById(macroId);
if (m == null) return string.Empty;
var model = new MacroModel(m);
// get as text, will render the control if any
var renderer = new MacroRenderer(plogger);
var macroContent = renderer.Render(model, elements, pageId);
var text = macroContent.GetAsText();
// remove hrefs
text = HrefRegex.Replace(text, match => "href=\"javascript:void(0)\"");
return text;
}
public static string MacroContentByHttp(int pageId, Guid pageVersion, Hashtable attributes, IMacroService macroService)
{
// though... we only support FullTrust now?
if (SystemUtilities.GetCurrentTrustLevel() != AspNetHostingPermissionLevel.Unrestricted)
return "<span style='color: red'>Cannot render macro content in the rich text editor when the application is running in a Partial Trust environment</span>";
var tempAlias = attributes["macroalias"]?.ToString() ?? attributes["macroAlias"].ToString();
var m = macroService.GetByAlias(tempAlias);
if (m == null) return string.Empty;
var macro = new MacroModel(m);
if (macro.RenderInEditor == false)
return ShowNoMacroContent(macro);
var querystring = $"umbPageId={pageId}&umbVersionId={pageVersion}";
var ide = attributes.GetEnumerator();
while (ide.MoveNext())
querystring += $"&umb_{ide.Key}={HttpContext.Current.Server.UrlEncode((ide.Value ?? String.Empty).ToString())}";
// create a new 'HttpWebRequest' object to the mentioned URL.
var useSsl = Current.Configs.Global().UseHttps;
var protocol = useSsl ? "https" : "http";
var currentRequest = HttpContext.Current.Request;
var serverVars = currentRequest.ServerVariables;
var umbracoDir = IOHelper.ResolveUrl(SystemDirectories.Umbraco);
var url = $"{protocol}://{serverVars["SERVER_NAME"]}:{serverVars["SERVER_PORT"]}{umbracoDir}/macroResultWrapper.aspx?{querystring}";
var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);
// allows for validation of SSL conversations (to bypass SSL errors in debug mode!)
ServicePointManager.ServerCertificateValidationCallback += ValidateRemoteCertificate;
// propagate the user's context
// TODO: this is the worst thing ever.
// also will not work if people decide to put their own custom auth system in place.
var inCookie = currentRequest.Cookies[Current.Configs.Settings().Security.AuthCookieName];
if (inCookie == null) throw new NullReferenceException("No auth cookie found");
var cookie = new Cookie(inCookie.Name, inCookie.Value, inCookie.Path, serverVars["SERVER_NAME"]);
myHttpWebRequest.CookieContainer = new CookieContainer();
myHttpWebRequest.CookieContainer.Add(cookie);
// assign the response object of 'HttpWebRequest' to a 'HttpWebResponse' variable.
HttpWebResponse myHttpWebResponse = null;
var text = string.Empty;
try
{
myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
if (myHttpWebResponse.StatusCode == HttpStatusCode.OK)
{
var streamResponse = myHttpWebResponse.GetResponseStream();
if (streamResponse == null)
throw new Exception("Internal error, no response stream.");
var streamRead = new StreamReader(streamResponse);
var readBuff = new char[256];
var count = streamRead.Read(readBuff, 0, 256);
while (count > 0)
{
var outputData = new string(readBuff, 0, count);
text += outputData;
count = streamRead.Read(readBuff, 0, 256);
}
streamResponse.Close();
streamRead.Close();
// find the content of a form
const string grabStart = "<!-- grab start -->";
const string grabEnd = "<!-- grab end -->";
var grabStartPos = text.InvariantIndexOf(grabStart) + grabStart.Length;
var grabEndPos = text.InvariantIndexOf(grabEnd) - grabStartPos;
text = text.Substring(grabStartPos, grabEndPos);
}
else
{
text = ShowNoMacroContent(macro);
}
}
catch (Exception)
{
text = ShowNoMacroContent(macro);
}
finally
{
// release the HttpWebResponse Resource.
myHttpWebResponse?.Close();
}
return text.Replace("\n", string.Empty).Replace("\r", string.Empty);
}
private static string ShowNoMacroContent(MacroModel model)
{
var name = HttpUtility.HtmlEncode(model.Name); // safe
return $"<span style=\"color: green\"><strong>{name}</strong><br />No macro content available for WYSIWYG editing</span>";
}
private static bool ValidateRemoteCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors policyErrors
)
{
// allow any old dodgy certificate in debug mode
return GlobalSettings.DebugMode || policyErrors == SslPolicyErrors.None;
}
#endregion
}
public class MacroRenderingEventArgs : EventArgs
{
public MacroRenderingEventArgs(Hashtable pageElements, int pageId)
{
PageElements = pageElements;
PageId = pageId;
}
public int PageId { get; }
public Hashtable PageElements { get; }
}
}

View File

@@ -30,14 +30,13 @@ namespace Umbraco.Web.Macros
/// </remarks>
internal PublishedContentHashtableConverter(PublishedRequest frequest)
{
if (!frequest.HasPublishedContent)
throw new ArgumentException("Document request has no node.", "frequest");
throw new ArgumentException("Document request has no node.", nameof(frequest));
PopulatePageData(frequest.PublishedContent.Id,
frequest.PublishedContent.Name, frequest.PublishedContent.ContentType.Id, frequest.PublishedContent.ContentType.Alias,
frequest.PublishedContent.WriterName, frequest.PublishedContent.CreatorName, frequest.PublishedContent.CreateDate, frequest.PublishedContent.UpdateDate,
frequest.PublishedContent.Path, frequest.PublishedContent.Parent == null ? -1 : frequest.PublishedContent.Parent.Id);
frequest.PublishedContent.Path, frequest.PublishedContent.Parent?.Id ?? -1);
if (frequest.HasTemplate)
{
@@ -54,12 +53,12 @@ namespace Umbraco.Web.Macros
/// <param name="doc"></param>
internal PublishedContentHashtableConverter(IPublishedContent doc)
{
if (doc == null) throw new ArgumentNullException("doc");
if (doc == null) throw new ArgumentNullException(nameof(doc));
PopulatePageData(doc.Id,
doc.Name, doc.ContentType.Id, doc.ContentType.Alias,
doc.WriterName, doc.CreatorName, doc.CreateDate, doc.UpdateDate,
doc.Path, doc.Parent == null ? -1 : doc.Parent.Id);
doc.Path, doc.Parent?.Id ?? -1);
if (doc.TemplateId.HasValue)
{
@@ -132,6 +131,7 @@ namespace Umbraco.Web.Macros
/// </summary>
public Hashtable Elements { get; } = new Hashtable();
#region PublishedContent
private class PagePublishedProperty : PublishedPropertyBase

View File

@@ -9,12 +9,14 @@ namespace Umbraco.Web.Models.Mapping
internal class RedirectUrlMapperProfile : Profile
{
public RedirectUrlMapperProfile()
public RedirectUrlMapperProfile(IUmbracoContextAccessor umbracoContextAccessor)
{
CreateMap<IRedirectUrl, ContentRedirectUrl>()
.ForMember(x => x.OriginalUrl, expression => expression.MapFrom(item => Current.UmbracoContext.UrlProvider.GetUrlFromRoute(item.ContentId, item.Url, item.Culture)))
.ForMember(x => x.DestinationUrl, expression => expression.MapFrom(item => item.ContentId > 0 ? new UmbracoHelper(Current.UmbracoContext, Current.Services).Url(item.ContentId, item.Culture) : "#"))
.ForMember(x => x.DestinationUrl, expression => expression.MapFrom(item => item.ContentId > 0 ? GetUrl(umbracoContextAccessor, item) : "#"))
.ForMember(x => x.RedirectId, expression => expression.MapFrom(item => item.Key));
}
private static string GetUrl(IUmbracoContextAccessor umbracoContextAccessor, IRedirectUrl item) => umbracoContextAccessor?.UmbracoContext?.UrlProvider?.GetUrl(item.Id, item.Culture);
}
}

View File

@@ -22,10 +22,10 @@ namespace Umbraco.Web.Models
MacroId = macroId;
}
public IPublishedContent Content { get; private set; }
public string MacroName { get; private set; }
public string MacroAlias { get; private set; }
public int MacroId { get; private set; }
public IDictionary<string, object> MacroParameters { get; private set; }
public IPublishedContent Content { get; }
public string MacroName { get; }
public string MacroAlias { get; }
public int MacroId { get; }
public IDictionary<string, object> MacroParameters { get; }
}
}

View File

@@ -77,8 +77,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Exposes an UmbracoHelper
/// </summary>
protected UmbracoHelper Umbraco => _helper
?? (_helper = new UmbracoHelper(Current.UmbracoContext, Current.Services));
protected UmbracoHelper Umbraco => _helper ?? (_helper = Current.Factory.GetInstance<UmbracoHelper>());
public override void OnActionExecuted(ActionExecutedContext filterContext)
{

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using AuthorizeAttribute = System.Web.Mvc.AuthorizeAttribute;
using Umbraco.Core;
using Umbraco.Web.Composing;
using Umbraco.Web.Security;
using Umbraco.Core.Composing;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Web.Mvc
{
@@ -14,35 +15,6 @@ namespace Umbraco.Web.Mvc
/// </summary>
public sealed class MemberAuthorizeAttribute : AuthorizeAttribute
{
// see note in HttpInstallAuthorizeAttribute
private readonly UmbracoContext _umbracoContext;
private UmbracoContext UmbracoContext => _umbracoContext ?? Current.UmbracoContext;
/// <summary>
/// THIS SHOULD BE ONLY USED FOR UNIT TESTS
/// </summary>
/// <param name="umbracoContext"></param>
public MemberAuthorizeAttribute(UmbracoContext umbracoContext)
{
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
_umbracoContext = umbracoContext;
}
public MemberAuthorizeAttribute()
{
}
/// <summary>
/// Flag for whether to allow all site visitors or just authenticated members
/// </summary>
/// <remarks>
/// This is the same as applying the [AllowAnonymous] attribute
/// </remarks>
[Obsolete("Use [AllowAnonymous] instead")]
public bool AllowAll { get; set; }
/// <summary>
/// Comma delimited list of allowed member types
/// </summary>
@@ -70,17 +42,15 @@ namespace Umbraco.Web.Mvc
var members = new List<int>();
foreach (var s in AllowMembers.Split(','))
{
int id;
if (int.TryParse(s, out id))
if (int.TryParse(s, out var id))
{
members.Add(id);
}
}
return UmbracoContext.Security.IsMemberAuthorized(AllowAll,
AllowType.Split(','),
AllowGroup.Split(','),
members);
var helper = Current.Factory.GetInstance<MembershipHelper>();
return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members);
}
/// <summary>

View File

@@ -20,8 +20,6 @@ namespace Umbraco.Web.Mvc
private static readonly ConcurrentDictionary<Type, PluginControllerMetadata> MetadataStorage
= new ConcurrentDictionary<Type, PluginControllerMetadata>();
private UmbracoHelper _umbracoHelper;
// for debugging purposes
internal Guid InstanceId { get; } = Guid.NewGuid();
@@ -70,18 +68,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Gets the Umbraco helper.
/// </summary>
public UmbracoHelper Umbraco
{
get
{
return _umbracoHelper
?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services));
}
internal set // tests
{
_umbracoHelper = value;
}
}
public UmbracoHelper Umbraco { get; }
/// <summary>
/// Gets metadata for this instance.
@@ -95,12 +82,13 @@ namespace Umbraco.Web.Mvc
Current.Factory.GetInstance<ServiceContext>(),
Current.Factory.GetInstance<AppCaches>(),
Current.Factory.GetInstance<ILogger>(),
Current.Factory.GetInstance<IProfilingLogger>()
Current.Factory.GetInstance<IProfilingLogger>(),
Current.Factory.GetInstance<UmbracoHelper>()
)
{
}
protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
protected PluginController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
{
UmbracoContext = umbracoContext;
DatabaseFactory = databaseFactory;
@@ -108,6 +96,7 @@ namespace Umbraco.Web.Mvc
AppCaches = appCaches;
Logger = logger;
ProfilingLogger = profilingLogger;
Umbraco = umbracoHelper;
}
/// <summary>

View File

@@ -23,8 +23,8 @@ namespace Umbraco.Web.Mvc
ActionInvoker = new RenderActionInvoker();
}
public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger)
public RenderMvcController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper)
{
ActionInvoker = new RenderActionInvoker();
}
@@ -32,7 +32,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Gets the Umbraco context.
/// </summary>
public override UmbracoContext UmbracoContext => PublishedRequest.UmbracoContext;
public override UmbracoContext UmbracoContext => PublishedRequest.UmbracoContext; //TODO: Why?
/// <summary>
/// Gets the current content item.

View File

@@ -19,8 +19,8 @@ namespace Umbraco.Web.Mvc
protected SurfaceController()
{ }
protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger)
protected SurfaceController(UmbracoContext umbracoContext, IUmbracoDatabaseFactory databaseFactory, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
: base(umbracoContext, databaseFactory, services, appCaches, logger, profilingLogger, umbracoHelper)
{ }
/// <summary>

View File

@@ -18,10 +18,12 @@ namespace Umbraco.Web.Mvc
public abstract class UmbracoAuthorizedController : UmbracoController
{
protected UmbracoAuthorizedController()
{ }
{
}
protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
: base(globalSettings, umbracoContext, services, appCaches, logger, profilingLogger)
{ }
protected UmbracoAuthorizedController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, services, appCaches, profilingLogger, umbracoHelper)
{
}
}
}

View File

@@ -17,15 +17,13 @@ namespace Umbraco.Web.Mvc
/// </summary>
public abstract class UmbracoController : Controller
{
private UmbracoHelper _umbracoHelper;
// for debugging purposes
internal Guid InstanceId { get; } = Guid.NewGuid();
/// <summary>
/// Gets or sets the Umbraco context.
/// </summary>
public virtual IGlobalSettings GlobalSettings { get; set; }
public IGlobalSettings GlobalSettings { get; set; }
/// <summary>
/// Gets or sets the Umbraco context.
@@ -62,8 +60,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Gets the Umbraco helper.
/// </summary>
public UmbracoHelper Umbraco => _umbracoHelper
?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services));
public UmbracoHelper Umbraco { get; }
/// <summary>
/// Gets the web security helper.
@@ -76,20 +73,21 @@ namespace Umbraco.Web.Mvc
Current.Factory.GetInstance<UmbracoContext>(),
Current.Factory.GetInstance<ServiceContext>(),
Current.Factory.GetInstance<AppCaches>(),
Current.Factory.GetInstance<ILogger>(),
Current.Factory.GetInstance<IProfilingLogger>()
Current.Factory.GetInstance<IProfilingLogger>(),
Current.Factory.GetInstance<UmbracoHelper>()
)
{
}
protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, ILogger logger, IProfilingLogger profilingLogger)
protected UmbracoController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, UmbracoHelper umbracoHelper)
{
GlobalSettings = globalSettings;
UmbracoContext = umbracoContext;
Services = services;
AppCaches = appCaches;
Logger = logger;
Logger = profilingLogger;
ProfilingLogger = profilingLogger;
Umbraco = umbracoHelper;
}
}
}

View File

@@ -7,6 +7,7 @@ using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
using Umbraco.Core.IO;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
@@ -84,7 +85,7 @@ namespace Umbraco.Web.Mvc
/// <summary>
/// Gets the Umbraco helper.
/// </summary>
public virtual UmbracoHelper Umbraco
public UmbracoHelper Umbraco
{
get
{
@@ -94,9 +95,12 @@ namespace Umbraco.Web.Mvc
var content = model as IPublishedContent;
if (content == null && model is IContentModel)
content = ((IContentModel) model).Content;
_helper = content == null
? new UmbracoHelper(UmbracoContext, Services)
: new UmbracoHelper(UmbracoContext, Services, content);
_helper = Current.UmbracoHelper;
if (content != null)
_helper.AssignedContentItem = content;
return _helper;
}
}

View File

@@ -20,12 +20,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
public class MacroContainerValueConverter : PropertyValueConverterBase
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ServiceContext _services;
private readonly IMacroRenderer _macroRenderer;
public MacroContainerValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services)
public MacroContainerValueConverter(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer)
{
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_services = services ?? throw new ArgumentNullException(nameof(services));
_macroRenderer = macroRenderer ?? throw new ArgumentNullException(nameof(macroRenderer));
}
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -48,14 +48,14 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
{
var sb = new StringBuilder();
var umbracoHelper = new UmbracoHelper(umbracoContext, _services);
MacroTagParser.ParseMacros(
source,
//callback for when text block is found
textBlock => sb.Append(textBlock),
//callback for when macro syntax is found
(macroAlias, macroAttributes) => sb.Append(umbracoHelper.RenderMacro(
(macroAlias, macroAttributes) => sb.Append(_macroRenderer.Render(
macroAlias,
umbracoContext.PublishedRequest?.PublishedContent,
//needs to be explicitly casted to Dictionary<string, object>
macroAttributes.ConvertTo(x => (string)x, x => x)).ToString()));

View File

@@ -21,7 +21,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
public class RteMacroRenderingValueConverter : TinyMceValueConverter
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly ServiceContext _services;
private readonly IMacroRenderer _macroRenderer;
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
@@ -30,10 +30,10 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return PropertyCacheLevel.Snapshot;
}
public RteMacroRenderingValueConverter(IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services)
public RteMacroRenderingValueConverter(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer)
{
_umbracoContextAccessor = umbracoContextAccessor;
_services = services;
_macroRenderer = macroRenderer;
}
// NOT thread-safe over a request because it modifies the
@@ -47,14 +47,14 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
{
var sb = new StringBuilder();
var umbracoHelper = new UmbracoHelper(umbracoContext, _services);
MacroTagParser.ParseMacros(
source,
//callback for when text block is found
textBlock => sb.Append(textBlock),
//callback for when macro syntax is found
(macroAlias, macroAttributes) => sb.Append(umbracoHelper.RenderMacro(
(macroAlias, macroAttributes) => sb.Append(_macroRenderer.Render(
macroAlias,
umbracoContext.PublishedRequest?.PublishedContent,
//needs to be explicitly casted to Dictionary<string, object>
macroAttributes.ConvertTo(x => (string)x, x => x)).ToString()));

View File

@@ -279,7 +279,6 @@ namespace Umbraco.Web.Routing
/// <summary>
/// Resets the template.
/// </summary>
/// <remarks>The <c>RenderingEngine</c> becomes unknown.</remarks>
public void ResetTemplate()
{
EnsureWriteable();

View File

@@ -197,9 +197,6 @@ namespace Umbraco.Web.Routing
// handlers like default.aspx will want it and most macros currently need it
frequest.LegacyContentHashTable = new PublishedContentHashtableConverter(frequest);
// used by many legacy objects
frequest.UmbracoContext.HttpContext.Items["pageElements"] = frequest.LegacyContentHashTable.Elements;
return true;
}
@@ -239,9 +236,7 @@ namespace Umbraco.Web.Routing
// assign the legacy page back to the docrequest
// handlers like default.aspx will want it and most macros currently need it
request.LegacyContentHashTable = new PublishedContentHashtableConverter(request);
// this is used by many legacy objects
request.UmbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements;
}
#endregion

View File

@@ -23,6 +23,7 @@ using Umbraco.Web.Dictionary;
using Umbraco.Web.Editors;
using Umbraco.Web.Features;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Macros;
using Umbraco.Web.Media.EmbedProviders;
using Umbraco.Web.Models.PublishedContent;
using Umbraco.Web.Mvc;
@@ -33,6 +34,7 @@ using Umbraco.Web.Security;
using Umbraco.Web.Security.Providers;
using Umbraco.Web.Services;
using Umbraco.Web.SignalR;
using Umbraco.Web.Templates;
using Umbraco.Web.Tour;
using Umbraco.Web.Trees;
using Umbraco.Web.WebApi;
@@ -86,8 +88,19 @@ namespace Umbraco.Web.Runtime
// TODO: stop doing this
composition.Register(factory => factory.GetInstance<IUmbracoContextAccessor>().UmbracoContext, Lifetime.Request);
// register the umbraco helper
composition.RegisterUnique<UmbracoHelper>();
composition.Register<IPublishedContentQuery>(factory =>
{
var umbCtx = factory.GetInstance<IUmbracoContextAccessor>();
return new PublishedContentQuery(umbCtx.UmbracoContext.ContentCache, umbCtx.UmbracoContext.MediaCache, factory.GetInstance<IVariationContextAccessor>());
}, Lifetime.Request);
composition.Register<ITagQuery, TagQuery>(Lifetime.Request);
composition.RegisterUnique<ITemplateRenderer, TemplateRenderer>();
composition.RegisterUnique<IMacroRenderer, MacroRenderer>();
composition.RegisterUnique<IUmbracoComponentRenderer, UmbracoComponentRenderer>();
// register the umbraco helper - this is Transient! very important!
composition.Register<UmbracoHelper>();
// register distributed cache
composition.RegisterUnique(f => new DistributedCache());

View File

@@ -23,16 +23,19 @@ namespace Umbraco.Web.Search
public class UmbracoTreeSearcher
{
private readonly IExamineManager _examineManager;
private readonly UmbracoContext _umbracoContext;
private readonly UmbracoHelper _umbracoHelper;
private readonly ILocalizationService _languageService;
private readonly IEntityService _entityService;
public UmbracoTreeSearcher(IExamineManager examineManager,
UmbracoContext umbracoContext,
UmbracoHelper umbracoHelper,
ILocalizationService languageService,
IEntityService entityService)
{
_examineManager = examineManager ?? throw new ArgumentNullException(nameof(examineManager));
_umbracoContext = umbracoContext;
_umbracoHelper = umbracoHelper ?? throw new ArgumentNullException(nameof(umbracoHelper));
_languageService = languageService;
_entityService = entityService;
@@ -61,9 +64,7 @@ namespace Umbraco.Web.Search
string type;
var indexName = Constants.UmbracoIndexes.InternalIndexName;
var fields = new[] { "id", "__NodeId" };
var umbracoContext = _umbracoHelper.UmbracoContext;
// TODO: WE should try to allow passing in a lucene raw query, however we will still need to do some manual string
// manipulation for things like start paths, member types, etc...
//if (Examine.ExamineExtensions.TryParseLuceneQuery(query))
@@ -86,12 +87,12 @@ namespace Umbraco.Web.Search
break;
case UmbracoEntityTypes.Media:
type = "media";
var allMediaStartNodes = umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService);
var allMediaStartNodes = _umbracoContext.Security.CurrentUser.CalculateMediaStartNodeIds(_entityService);
AppendPath(sb, UmbracoObjectTypes.Media, allMediaStartNodes, searchFrom, _entityService);
break;
case UmbracoEntityTypes.Document:
type = "content";
var allContentStartNodes = umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService);
var allContentStartNodes = _umbracoContext.Security.CurrentUser.CalculateContentStartNodeIds(_entityService);
AppendPath(sb, UmbracoObjectTypes.Document, allContentStartNodes, searchFrom, _entityService);
break;
default:

View File

@@ -599,20 +599,15 @@ namespace Umbraco.Web.Security
/// <summary>
/// Returns true or false if the currently logged in member is authorized based on the parameters provided
/// </summary>
/// <param name="allowAll"></param>
/// <param name="allowTypes"></param>
/// <param name="allowGroups"></param>
/// <param name="allowMembers"></param>
/// <returns></returns>
public virtual bool IsMemberAuthorized(
bool allowAll = false,
IEnumerable<string> allowTypes = null,
IEnumerable<string> allowGroups = null,
IEnumerable<int> allowMembers = null)
{
if (allowAll)
return true;
if (allowTypes == null)
allowTypes = Enumerable.Empty<string>();
if (allowGroups == null)

View File

@@ -33,30 +33,7 @@ namespace Umbraco.Web.Security
_userService = userService;
_globalSettings = globalSettings;
}
/// <summary>
/// Returns true or false if the currently logged in member is authorized based on the parameters provided
/// </summary>
/// <param name="allowAll"></param>
/// <param name="allowTypes"></param>
/// <param name="allowGroups"></param>
/// <param name="allowMembers"></param>
/// <returns></returns>
[Obsolete("Use MembershipHelper.IsMemberAuthorized instead")]
public bool IsMemberAuthorized(
bool allowAll = false,
IEnumerable<string> allowTypes = null,
IEnumerable<string> allowGroups = null,
IEnumerable<int> allowMembers = null)
{
if (Current.UmbracoContext == null)
{
return false;
}
var helper = Current.Factory.GetInstance<MembershipHelper>();
return helper.IsMemberAuthorized(allowAll, allowTypes, allowGroups, allowMembers);
}
private IUser _currentUser;
/// <summary>

View File

@@ -0,0 +1,12 @@
using System.IO;
namespace Umbraco.Web.Templates
{
/// <summary>
/// This is used purely for the RenderTemplate functionality in Umbraco
/// </summary>
public interface ITemplateRenderer
{
void Render(int pageId, int? altTemplateId, StringWriter writer);
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -9,6 +10,7 @@ using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.Routing;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Services;
using Umbraco.Web.Macros;
using Current = Umbraco.Web.Composing.Current;
@@ -21,92 +23,81 @@ namespace Umbraco.Web.Templates
/// <remarks>
/// This allows you to render an MVC template based purely off of a node id and an optional alttemplate id as string output.
/// </remarks>
internal class TemplateRenderer
internal class TemplateRenderer : ITemplateRenderer
{
private readonly UmbracoContext _umbracoContext;
private object _oldPageElements;
private PublishedRequest _oldPublishedRequest;
private object _oldAltTemplate;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IPublishedRouter _publishedRouter;
private readonly IFileService _fileService;
private readonly ILocalizationService _languageService;
private readonly IWebRoutingSection _webRoutingSection;
public TemplateRenderer(UmbracoContext umbracoContext, int pageId, int? altTemplateId)
public TemplateRenderer(IUmbracoContextAccessor umbracoContextAccessor, IPublishedRouter publishedRouter, IFileService fileService, ILocalizationService textService, IWebRoutingSection webRoutingSection)
{
PageId = pageId;
AltTemplateId = altTemplateId;
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
_umbracoContextAccessor = umbracoContextAccessor ?? throw new ArgumentNullException(nameof(umbracoContextAccessor));
_publishedRouter = publishedRouter ?? throw new ArgumentNullException(nameof(publishedRouter));
_fileService = fileService ?? throw new ArgumentNullException(nameof(fileService));
_languageService = textService ?? throw new ArgumentNullException(nameof(textService));
_webRoutingSection = webRoutingSection ?? throw new ArgumentNullException(nameof(webRoutingSection));
}
private IFileService FileService => Current.Services.FileService; // TODO: inject
private IPublishedRouter PublishedRouter => Core.Composing.Current.Factory.GetInstance<IPublishedRouter>(); // TODO: inject
/// <summary>
/// Gets/sets the page id for the template to render
/// </summary>
public int PageId { get; }
/// <summary>
/// Gets/sets the alt template to render if there is one
/// </summary>
public int? AltTemplateId { get; }
public void Render(StringWriter writer)
public void Render(int pageId, int? altTemplateId, StringWriter writer)
{
if (writer == null) throw new ArgumentNullException(nameof(writer));
// instantiate a request and process
// important to use CleanedUmbracoUrl - lowercase path-only version of the current url, though this isn't going to matter
// terribly much for this implementation since we are just creating a doc content request to modify it's properties manually.
var contentRequest = PublishedRouter.CreateRequest(_umbracoContext);
var contentRequest = _publishedRouter.CreateRequest(_umbracoContextAccessor.UmbracoContext);
var doc = contentRequest.UmbracoContext.ContentCache.GetById(PageId);
var doc = contentRequest.UmbracoContext.ContentCache.GetById(pageId);
if (doc == null)
{
writer.Write("<!-- Could not render template for Id {0}, the document was not found -->", PageId);
writer.Write("<!-- Could not render template for Id {0}, the document was not found -->", pageId);
return;
}
//in some cases the UmbracoContext will not have a PublishedContentRequest assigned to it if we are not in the
//execution of a front-end rendered page. In this case set the culture to the default.
//set the culture to the same as is currently rendering
if (_umbracoContext.PublishedRequest == null)
if (_umbracoContextAccessor.UmbracoContext.PublishedRequest == null)
{
var defaultLanguage = Current.Services.LocalizationService.GetAllLanguages().FirstOrDefault();
var defaultLanguage = _languageService.GetAllLanguages().FirstOrDefault();
contentRequest.Culture = defaultLanguage == null
? CultureInfo.CurrentUICulture
: defaultLanguage.CultureInfo;
}
else
{
contentRequest.Culture = _umbracoContext.PublishedRequest.Culture;
contentRequest.Culture = _umbracoContextAccessor.UmbracoContext.PublishedRequest.Culture;
}
//set the doc that was found by id
contentRequest.PublishedContent = doc;
//set the template, either based on the AltTemplate found or the standard template of the doc
var templateId = Current.Configs.Settings().WebRouting.DisableAlternativeTemplates || !AltTemplateId.HasValue
var templateId = _webRoutingSection.DisableAlternativeTemplates || !altTemplateId.HasValue
? doc.TemplateId
: AltTemplateId.Value;
: altTemplateId.Value;
if (templateId.HasValue)
contentRequest.TemplateModel = FileService.GetTemplate(templateId.Value);
contentRequest.TemplateModel = _fileService.GetTemplate(templateId.Value);
//if there is not template then exit
if (contentRequest.HasTemplate == false)
{
if (AltTemplateId.HasValue == false)
if (altTemplateId.HasValue == false)
{
writer.Write("<!-- Could not render template for Id {0}, the document's template was not found with id {0}-->", doc.TemplateId);
}
else
{
writer.Write("<!-- Could not render template for Id {0}, the altTemplate was not found with id {0}-->", AltTemplateId);
writer.Write("<!-- Could not render template for Id {0}, the altTemplate was not found with id {0}-->", altTemplateId);
}
return;
}
//First, save all of the items locally that we know are used in the chain of execution, we'll need to restore these
//after this page has rendered.
SaveExistingItems();
SaveExistingItems(out var oldPublishedRequest, out var oldAltTemplate);
try
{
@@ -119,7 +110,7 @@ namespace Umbraco.Web.Templates
finally
{
//restore items on context objects to continuing rendering the parent template
RestoreItems();
RestoreItems(oldPublishedRequest, oldAltTemplate);
}
}
@@ -134,11 +125,11 @@ namespace Umbraco.Web.Templates
//var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys
// .ToDictionary(key => key, key => context.Request.QueryString[key]);
var requestContext = new RequestContext(_umbracoContext.HttpContext, new RouteData()
var requestContext = new RequestContext(_umbracoContextAccessor.UmbracoContext.HttpContext, new RouteData()
{
Route = RouteTable.Routes["Umbraco_default"]
});
var routeHandler = new RenderRouteHandler(_umbracoContext, ControllerBuilder.Current.GetControllerFactory());
var routeHandler = new RenderRouteHandler(_umbracoContextAccessor, ControllerBuilder.Current.GetControllerFactory());
var routeDef = routeHandler.GetUmbracoRouteDefinition(requestContext, request);
var renderModel = new ContentModel(request.PublishedContent);
//manually add the action/controller, this is required by mvc
@@ -181,34 +172,29 @@ namespace Umbraco.Web.Templates
private void SetNewItemsOnContextObjects(PublishedRequest request)
{
// handlers like default.aspx will want it and most macros currently need it
request.LegacyContentHashTable = new PublishedContentHashtableConverter(request);
//now, set the new ones for this page execution
_umbracoContext.HttpContext.Items["pageElements"] = request.LegacyContentHashTable.Elements;
_umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null;
_umbracoContext.PublishedRequest = request;
_umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = null;
_umbracoContextAccessor.UmbracoContext.PublishedRequest = request;
}
/// <summary>
/// Save all items that we know are used for rendering execution to variables so we can restore after rendering
/// </summary>
private void SaveExistingItems()
private void SaveExistingItems(out PublishedRequest oldPublishedRequest, out object oldAltTemplate)
{
//Many objects require that these legacy items are in the http context items... before we render this template we need to first
//save the values in them so that we can re-set them after we render so the rest of the execution works as per normal
_oldPageElements = _umbracoContext.HttpContext.Items["pageElements"];
_oldPublishedRequest = _umbracoContext.PublishedRequest;
_oldAltTemplate = _umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate];
oldPublishedRequest = _umbracoContextAccessor.UmbracoContext.PublishedRequest;
oldAltTemplate = _umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate];
}
/// <summary>
/// Restores all items back to their context's to continue normal page rendering execution
/// </summary>
private void RestoreItems()
private void RestoreItems(PublishedRequest oldPublishedRequest, object oldAltTemplate)
{
_umbracoContext.PublishedRequest = _oldPublishedRequest;
_umbracoContext.HttpContext.Items["pageElements"] = _oldPageElements;
_umbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = _oldAltTemplate;
_umbracoContextAccessor.UmbracoContext.PublishedRequest = oldPublishedRequest;
_umbracoContextAccessor.UmbracoContext.HttpContext.Items[Core.Constants.Conventions.Url.AltTemplate] = oldAltTemplate;
}
}
}

View File

@@ -36,8 +36,8 @@ namespace Umbraco.Web.Trees
public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext,
ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger,
IRuntimeState runtimeState, ITreeService treeService)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
IRuntimeState runtimeState, ITreeService treeService, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_treeService = treeService;
}

View File

@@ -18,8 +18,8 @@ namespace Umbraco.Web.Trees
private readonly TreeAttribute _treeAttribute;
protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
protected TreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_treeAttribute = GetTreeAttribute();
}

View File

@@ -27,11 +27,12 @@ namespace Umbraco.Web.Trees
public abstract class TreeControllerBase : UmbracoAuthorizedApiController, ITree
{
protected TreeControllerBase()
{ }
{
}
protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{ }
protected TreeControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// The method called to render the contents of the tree structure

View File

@@ -143,6 +143,7 @@
<Compile Include="Logging\WebProfilerComponent.cs" />
<Compile Include="Logging\WebProfilerComposer.cs" />
<Compile Include="Logging\WebProfilerProvider.cs" />
<Compile Include="Macros\IMacroRenderer.cs" />
<Compile Include="Media\EmbedProviders\YouTube.cs" />
<Compile Include="Media\EmbedProviders\EmbedProviderBase.cs" />
<Compile Include="Media\EmbedProviders\EmbedProvidersCollection.cs" />
@@ -212,6 +213,7 @@
<Compile Include="PropertyEditors\MultiUrlPickerPropertyEditor.cs" />
<Compile Include="PropertyEditors\MultiUrlPickerValueEditor.cs" />
<Compile Include="PropertyEditors\ValueConverters\MultiUrlPickerValueConverter.cs" />
<Compile Include="Templates\ITemplateRenderer.cs" />
<Compile Include="Trees\BackOfficeSectionCollectionBuilder.cs" />
<Compile Include="Trees\MediaBackOfficeSection.cs" />
<Compile Include="Trees\MembersBackOfficeSection.cs" />

View File

@@ -2,6 +2,7 @@
using System.Security;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Web.Security;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Services;
@@ -11,10 +12,10 @@ namespace Umbraco.Web
public abstract class UmbracoAuthorizedHttpHandler : UmbracoHttpHandler
{
protected UmbracoAuthorizedHttpHandler()
{ }
{
}
protected UmbracoAuthorizedHttpHandler(UmbracoContext umbracoContext, ServiceContext services)
: base(umbracoContext, services)
protected UmbracoAuthorizedHttpHandler(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper, ServiceContext service, IProfilingLogger plogger) : base(umbracoContext, umbracoHelper, service, plogger)
{
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Collections;
using System.IO;
using System.Web;
@@ -6,6 +7,9 @@ using System.Web.UI;
using Umbraco.Core;
using Umbraco.Web.Templates;
using System.Collections.Generic;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Web.Composing;
using Umbraco.Web.Macros;
@@ -20,31 +24,34 @@ namespace Umbraco.Web
/// </remarks>
internal class UmbracoComponentRenderer : IUmbracoComponentRenderer
{
private readonly UmbracoContext _umbracoContext;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IMacroRenderer _macroRenderer;
private readonly ITemplateRenderer _templateRenderer;
public UmbracoComponentRenderer(UmbracoContext umbracoContext)
public UmbracoComponentRenderer(IUmbracoContextAccessor umbracoContextAccessor, IMacroRenderer macroRenderer, ITemplateRenderer templateRenderer)
{
_umbracoContext = umbracoContext;
_umbracoContextAccessor = umbracoContextAccessor;
_macroRenderer = macroRenderer;
_templateRenderer = templateRenderer ?? throw new ArgumentNullException(nameof(templateRenderer));
}
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="pageId"></param>
/// <param name="contentId"></param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
public IHtmlString RenderTemplate(int pageId, int? altTemplateId = null)
public IHtmlString RenderTemplate(int contentId, int? altTemplateId = null)
{
var templateRenderer = new TemplateRenderer(_umbracoContext, pageId, altTemplateId);
using (var sw = new StringWriter())
{
try
{
templateRenderer.Render(sw);
_templateRenderer.Render(contentId, altTemplateId, sw);
}
catch (Exception ex)
{
sw.Write("<!-- Error rendering template with id {0}: '{1}' -->", pageId, ex);
sw.Write("<!-- Error rendering template with id {0}: '{1}' -->", contentId, ex);
}
return new HtmlString(sw.ToString());
}
@@ -53,129 +60,107 @@ namespace Umbraco.Web
/// <summary>
/// Renders the macro with the specified alias.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <returns></returns>
public IHtmlString RenderMacro(string alias)
public IHtmlString RenderMacro(int contentId, string alias)
{
return RenderMacro(alias, new { });
return RenderMacro(contentId, alias, new { });
}
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
public IHtmlString RenderMacro(string alias, object parameters)
public IHtmlString RenderMacro(int contentId, string alias, object parameters)
{
return RenderMacro(alias, parameters.ToDictionary<object>());
return RenderMacro(contentId, alias, parameters.ToDictionary<object>());
}
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="contentId"></param>
/// <param name="alias">The alias.</param>
/// <param name="parameters">The parameters.</param>
/// <returns></returns>
public IHtmlString RenderMacro(string alias, IDictionary<string, object> parameters)
public IHtmlString RenderMacro(int contentId, string alias, IDictionary<string, object> parameters)
{
if (contentId == default)
throw new ArgumentException("Invalid content id " + contentId);
if (_umbracoContext.PublishedRequest == null)
{
throw new InvalidOperationException("Cannot render a macro when there is no current PublishedContentRequest.");
}
var content = _umbracoContextAccessor.UmbracoContext.ContentCache?.GetById(true, contentId);
return RenderMacro(alias, parameters, _umbracoContext.PublishedRequest.LegacyContentHashTable);
if (content == null)
throw new InvalidOperationException("Cannot render a macro, no content found by id " + contentId);
return RenderMacro(alias, parameters, content);
}
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="alias">The alias.</param>
/// <param name="alias">The macro alias.</param>
/// <param name="parameters">The parameters.</param>
/// <param name="umbracoPage">The legacy umbraco page object that is required for some macros</param>
/// <param name="content">The content used for macro rendering</param>
/// <returns></returns>
internal IHtmlString RenderMacro(string alias, IDictionary<string, object> parameters, PublishedContentHashtableConverter umbracoPage)
private IHtmlString RenderMacro(string alias, IDictionary<string, object> parameters, IPublishedContent content)
{
if (alias == null) throw new ArgumentNullException("alias");
if (umbracoPage == null) throw new ArgumentNullException("umbracoPage");
if (content == null) throw new ArgumentNullException(nameof(content));
var m = Current.Services.MacroService.GetByAlias(alias);
if (m == null)
throw new KeyNotFoundException("Could not find macro with alias " + alias);
return RenderMacro(new MacroModel(m), parameters, umbracoPage);
}
/// <summary>
/// Renders the macro with the specified alias, passing in the specified parameters.
/// </summary>
/// <param name="m">The macro.</param>
/// <param name="parameters">The parameters.</param>
/// <param name="umbracoPage">The legacy umbraco page object that is required for some macros</param>
/// <returns></returns>
internal IHtmlString RenderMacro(MacroModel m, IDictionary<string, object> parameters, PublishedContentHashtableConverter umbracoPage)
{
if (umbracoPage == null) throw new ArgumentNullException(nameof(umbracoPage));
if (m == null) throw new ArgumentNullException(nameof(m));
if (_umbracoContext.PageId == null)
{
throw new InvalidOperationException("Cannot render a macro when UmbracoContext.PageId is null.");
}
var macroProps = new Hashtable();
foreach (var i in parameters)
{
// TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method of macro.cs
// looks for a lower case match. WTF. the whole macro concept needs to be rewritten.
//NOTE: the value could have HTML encoded values, so we need to deal with that
macroProps.Add(i.Key.ToLowerInvariant(), (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value);
}
var renderer = new MacroRenderer(Current.ProfilingLogger);
var macroControl = renderer.Render(m, umbracoPage.Elements, _umbracoContext.PageId.Value, macroProps).GetAsControl();
// TODO: We are doing at ToLower here because for some insane reason the UpdateMacroModel method looks for a lower case match. the whole macro concept needs to be rewritten.
//NOTE: the value could have HTML encoded values, so we need to deal with that
var macroProps = parameters.ToDictionary(
x => x.Key.ToLowerInvariant(),
i => (i.Value is string) ? HttpUtility.HtmlDecode(i.Value.ToString()) : i.Value);
var macroControl = _macroRenderer.Render(alias, content, macroProps).GetAsControl();
string html;
if (macroControl is LiteralControl)
if (macroControl is LiteralControl control)
{
// no need to execute, we already have text
html = (macroControl as LiteralControl).Text;
html = control.Text;
}
else
{
var containerPage = new FormlessPage();
containerPage.Controls.Add(macroControl);
using (var output = new StringWriter())
using (var containerPage = new FormlessPage())
{
// .Execute() does a PushTraceContext/PopTraceContext and writes trace output straight into 'output'
// and I do not see how we could wire the trace context to the current context... so it creates dirty
// trace output right in the middle of the page.
//
// The only thing we can do is fully disable trace output while .Execute() runs and restore afterwards
// which means trace output is lost if the macro is a control (.ascx or user control) that is invoked
// from within Razor -- which makes sense anyway because the control can _not_ run correctly from
// within Razor since it will never be inserted into the page pipeline (which may even not exist at all
// if we're running MVC).
//
// I'm sure there's more things that will get lost with this context changing but I guess we'll figure
// those out as we go along. One thing we lose is the content type response output.
// http://issues.umbraco.org/issue/U4-1599 if it is setup during the macro execution. So
// here we'll save the content type response and reset it after execute is called.
containerPage.Controls.Add(macroControl);
var contentType = _umbracoContext.HttpContext.Response.ContentType;
var traceIsEnabled = containerPage.Trace.IsEnabled;
containerPage.Trace.IsEnabled = false;
_umbracoContext.HttpContext.Server.Execute(containerPage, output, true);
containerPage.Trace.IsEnabled = traceIsEnabled;
//reset the content type
_umbracoContext.HttpContext.Response.ContentType = contentType;
using (var output = new StringWriter())
{
// .Execute() does a PushTraceContext/PopTraceContext and writes trace output straight into 'output'
// and I do not see how we could wire the trace context to the current context... so it creates dirty
// trace output right in the middle of the page.
//
// The only thing we can do is fully disable trace output while .Execute() runs and restore afterwards
// which means trace output is lost if the macro is a control (.ascx or user control) that is invoked
// from within Razor -- which makes sense anyway because the control can _not_ run correctly from
// within Razor since it will never be inserted into the page pipeline (which may even not exist at all
// if we're running MVC).
//
// I'm sure there's more things that will get lost with this context changing but I guess we'll figure
// those out as we go along. One thing we lose is the content type response output.
// http://issues.umbraco.org/issue/U4-1599 if it is setup during the macro execution. So
// here we'll save the content type response and reset it after execute is called.
//Now, we need to ensure that local links are parsed
html = TemplateUtilities.ParseInternalLinks(output.ToString(), _umbracoContext.UrlProvider);
var contentType = _umbracoContextAccessor.UmbracoContext.HttpContext.Response.ContentType;
var traceIsEnabled = containerPage.Trace.IsEnabled;
containerPage.Trace.IsEnabled = false;
_umbracoContextAccessor.UmbracoContext.HttpContext.Server.Execute(containerPage, output, true);
containerPage.Trace.IsEnabled = traceIsEnabled;
//reset the content type
_umbracoContextAccessor.UmbracoContext.HttpContext.Response.ContentType = contentType;
//Now, we need to ensure that local links are parsed
html = TemplateUtilities.ParseInternalLinks(output.ToString(), _umbracoContextAccessor.UmbracoContext.UrlProvider);
}
}
}
return new HtmlString(html);

View File

@@ -281,29 +281,7 @@ namespace Umbraco.Web
|| string.IsNullOrEmpty(request["umbdebug"]) == false);
}
}
/// <summary>
/// Gets the current page ID, or <c>null</c> if no page ID is available (e.g. a custom page).
/// </summary>
public int? PageId
{
get
{
try
{
// This was changed but the comments used to refer to
// macros in the backoffice not working with this Id
// it's probably not a problem any more though. Old comment:
// https://github.com/umbraco/Umbraco-CMS/blob/7a615133ff9de84ee667fb7794169af65e2b4d7a/src/Umbraco.Web/UmbracoContext.cs#L256
return Current.PublishedRequest.PublishedContent.Id;
}
catch
{
return null;
}
}
}
/// <summary>
/// Determines whether the current user is in a preview mode and browsing the site (ie. not in the admin UI)
/// </summary>
@@ -312,7 +290,7 @@ namespace Umbraco.Web
get
{
if (_previewing.HasValue == false) DetectPreviewMode();
return _previewing.Value;
return _previewing ?? false;
}
private set => _previewing = value;
}

View File

@@ -8,139 +8,89 @@ using Umbraco.Core.Dictionary;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Services;
using Umbraco.Core.Xml;
using Umbraco.Core.Composing;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Web
{
using Examine = global::Examine;
/// <summary>
/// A helper class that provides many useful methods and functionality for using Umbraco in templates
/// </summary>
public class UmbracoHelper : IUmbracoComponentRenderer
/// <remarks>
/// This object is a request based lifetime
/// </remarks>
public class UmbracoHelper
{
private static readonly HtmlStringUtilities StringUtilities = new HtmlStringUtilities();
private readonly UmbracoContext _umbracoContext;
private readonly IPublishedContent _currentPage;
private readonly ServiceContext _services;
private IPublishedContent _currentPage;
private IUmbracoComponentRenderer _componentRenderer;
private IPublishedContentQuery _query;
private MembershipHelper _membershipHelper;
private ITagQuery _tag;
private readonly IUmbracoComponentRenderer _componentRenderer;
private readonly ICultureDictionaryFactory _cultureDictionaryFactory;
private ICultureDictionary _cultureDictionary;
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoHelper"/> class.
/// Initializes a new instance of <see cref="UmbracoHelper"/>.
/// </summary>
/// <remarks>For tests.</remarks>
internal UmbracoHelper(UmbracoContext umbracoContext, IPublishedContent content,
ITagQuery tagQuery,
ICultureDictionary cultureDictionary,
/// <param name="umbracoContext">An Umbraco context.</param>
/// <param name="tagQuery"></param>
/// <param name="cultureDictionary"></param>
/// <param name="componentRenderer"></param>
/// <param name="publishedContentQuery"></param>
/// <param name="membershipHelper"></param>
/// <remarks>Sets the current page to the context's published content request's content item.</remarks>
public UmbracoHelper(UmbracoContext umbracoContext, ITagQuery tagQuery,
ICultureDictionaryFactory cultureDictionary,
IUmbracoComponentRenderer componentRenderer,
MembershipHelper membershipHelper,
ServiceContext services)
IPublishedContentQuery publishedContentQuery,
MembershipHelper membershipHelper)
{
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
_tag = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery));
_cultureDictionary = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary));
TagQuery = tagQuery ?? throw new ArgumentNullException(nameof(tagQuery));
_cultureDictionaryFactory = cultureDictionary ?? throw new ArgumentNullException(nameof(cultureDictionary));
_componentRenderer = componentRenderer ?? throw new ArgumentNullException(nameof(componentRenderer));
_membershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper));
_currentPage = content ?? throw new ArgumentNullException(nameof(content));
_services = services ?? throw new ArgumentNullException(nameof(services));
MembershipHelper = membershipHelper ?? throw new ArgumentNullException(nameof(membershipHelper));
ContentQuery = publishedContentQuery ?? throw new ArgumentNullException(nameof(publishedContentQuery));
if (_umbracoContext.IsFrontEndUmbracoRequest)
_currentPage = _umbracoContext.PublishedRequest.PublishedContent;
}
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoHelper"/> class.
/// Initializes a new empty instance of <see cref="UmbracoHelper"/>.
/// </summary>
/// <remarks>For tests - nothing is initialized.</remarks>
internal UmbracoHelper()
{ }
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoHelper"/> class with an Umbraco context
/// and a specific content item.
/// </summary>
/// <param name="umbracoContext">An Umbraco context.</param>
/// <param name="content">A content item.</param>
/// <param name="services">A services context.</param>
/// <remarks>Sets the current page to the supplied content item.</remarks>
public UmbracoHelper(UmbracoContext umbracoContext, ServiceContext services, IPublishedContent content)
: this(umbracoContext, services)
{
_currentPage = content ?? throw new ArgumentNullException(nameof(content));
}
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoHelper"/> class with an Umbraco context.
/// </summary>
/// <param name="umbracoContext">An Umbraco context.</param>
/// <param name="services">A services context.</param>
/// <remarks>Sets the current page to the context's published content request's content item.</remarks>
public UmbracoHelper(UmbracoContext umbracoContext, ServiceContext services)
{
_services = services ?? throw new ArgumentNullException(nameof(services));
_umbracoContext = umbracoContext ?? throw new ArgumentNullException(nameof(umbracoContext));
if (_umbracoContext.IsFrontEndUmbracoRequest)
_currentPage = _umbracoContext.PublishedRequest.PublishedContent;
}
#endregion
/// <summary>
/// Gets the tag context.
/// </summary>
public ITagQuery TagQuery => _tag ??
(_tag = new TagQuery(_services.TagService, ContentQuery));
public ITagQuery TagQuery { get; }
/// <summary>
/// Gets the query context.
/// </summary>
public IPublishedContentQuery ContentQuery => _query ??
(_query = new PublishedContentQuery(UmbracoContext.ContentCache, UmbracoContext.MediaCache, UmbracoContext.VariationContextAccessor));
/// <summary>
/// Gets the Umbraco context.
/// </summary>
public UmbracoContext UmbracoContext
{
get
{
if (_umbracoContext == null)
throw new NullReferenceException("UmbracoContext has not been set.");
return _umbracoContext;
}
}
public IPublishedContentQuery ContentQuery { get; }
/// <summary>
/// Gets the membership helper.
/// </summary>
public MembershipHelper MembershipHelper => _membershipHelper
?? (_membershipHelper = Current.Factory.GetInstance<MembershipHelper>());
public MembershipHelper MembershipHelper { get; }
/// <summary>
/// Gets the url provider.
/// </summary>
public UrlProvider UrlProvider => UmbracoContext.UrlProvider;
public UrlProvider UrlProvider => _umbracoContext.UrlProvider;
/// <summary>
/// Gets the component renderer.
/// </summary>
public IUmbracoComponentRenderer UmbracoComponentRenderer => _componentRenderer
?? (_componentRenderer = new UmbracoComponentRenderer(UmbracoContext));
/// <summary>
/// Returns the current <seealso cref="IPublishedContent"/> item
/// assigned to the UmbracoHelper.
/// Gets (or sets) the current <see cref="IPublishedContent"/> item assigned to the UmbracoHelper.
/// </summary>
/// <remarks>
/// <para>
@@ -173,17 +123,18 @@ namespace Umbraco.Web
);
}
set => _currentPage = value;
}
/// <summary>
/// Renders the template for the specified pageId and an optional altTemplateId
/// </summary>
/// <param name="pageId"></param>
/// <param name="contentId"></param>
/// <param name="altTemplateId">If not specified, will use the template assigned to the node</param>
/// <returns></returns>
public IHtmlString RenderTemplate(int pageId, int? altTemplateId = null)
public IHtmlString RenderTemplate(int contentId, int? altTemplateId = null)
{
return UmbracoComponentRenderer.RenderTemplate(pageId, altTemplateId);
return _componentRenderer.RenderTemplate(contentId, altTemplateId);
}
#region RenderMacro
@@ -195,7 +146,7 @@ namespace Umbraco.Web
/// <returns></returns>
public IHtmlString RenderMacro(string alias)
{
return UmbracoComponentRenderer.RenderMacro(alias, new { });
return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, new { });
}
/// <summary>
@@ -206,7 +157,7 @@ namespace Umbraco.Web
/// <returns></returns>
public IHtmlString RenderMacro(string alias, object parameters)
{
return UmbracoComponentRenderer.RenderMacro(alias, parameters.ToDictionary<object>());
return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, parameters.ToDictionary<object>());
}
/// <summary>
@@ -217,7 +168,7 @@ namespace Umbraco.Web
/// <returns></returns>
public IHtmlString RenderMacro(string alias, IDictionary<string, object> parameters)
{
return UmbracoComponentRenderer.RenderMacro(alias, parameters);
return _componentRenderer.RenderMacro(_umbracoContext.PublishedRequest?.PublishedContent?.Id ?? 0, alias, parameters);
}
#endregion
@@ -254,7 +205,7 @@ namespace Umbraco.Web
/// Returns the ICultureDictionary for access to dictionary items
/// </summary>
public ICultureDictionary CultureDictionary => _cultureDictionary
?? (_cultureDictionary = Current.CultureDictionaryFactory.CreateDictionary());
?? (_cultureDictionary = _cultureDictionaryFactory.CreateDictionary());
#endregion
@@ -287,6 +238,7 @@ namespace Umbraco.Web
/// Gets the url of a content identified by its identifier.
/// </summary>
/// <param name="contentId">The content identifier.</param>
/// <param name="culture"></param>
/// <returns>The url for the content.</returns>
public string Url(int contentId, string culture = null)
{
@@ -454,11 +406,9 @@ namespace Umbraco.Web
private IEnumerable<IPublishedContent> ContentForObjects(IEnumerable<object> ids)
{
var idsA = ids.ToArray();
IEnumerable<int> intIds;
if (ConvertIdsObjectToInts(idsA, out intIds))
if (ConvertIdsObjectToInts(idsA, out var intIds))
return ContentQuery.Content(intIds);
IEnumerable<Guid> guidIds;
if (ConvertIdsObjectToGuids(idsA, out guidIds))
if (ConvertIdsObjectToGuids(idsA, out var guidIds))
return ContentQuery.Content(guidIds);
return Enumerable.Empty<IPublishedContent>();
}
@@ -638,12 +588,7 @@ namespace Umbraco.Web
public IPublishedContent Media(Guid id)
{
// TODO: This is horrible but until the media cache properly supports GUIDs we have no choice here and
// currently there won't be any way to add this method correctly to `ITypedPublishedContentQuery` without breaking an interface and adding GUID support for media
var entityService = Current.Services.EntityService; // TODO: inject
var mediaAttempt = entityService.GetId(id, UmbracoObjectTypes.Media);
return mediaAttempt.Success ? ContentQuery.Media(mediaAttempt.Result) : null;
return ContentQuery.Media(id);
}
/// <summary>
@@ -696,12 +641,10 @@ namespace Umbraco.Web
private IEnumerable<IPublishedContent> MediaForObjects(IEnumerable<object> ids)
{
var idsA = ids.ToArray();
IEnumerable<int> intIds;
if (ConvertIdsObjectToInts(idsA, out intIds))
if (ConvertIdsObjectToInts(idsA, out var intIds))
return ContentQuery.Media(intIds);
//IEnumerable<Guid> guidIds;
//if (ConvertIdsObjectToGuids(idsA, out guidIds))
// return ContentQuery.Media(guidIds);
if (ConvertIdsObjectToGuids(idsA, out var guidIds))
return ContentQuery.Media(guidIds);
return Enumerable.Empty<IPublishedContent>();
}

View File

@@ -14,19 +14,16 @@ namespace Umbraco.Web
private UrlHelper _url;
protected UmbracoHttpHandler()
: this(Current.UmbracoContext, Current.Services)
: this(Current.UmbracoContext, Current.UmbracoHelper, Current.Services, Current.ProfilingLogger)
{ }
protected UmbracoHttpHandler(UmbracoContext umbracoContext, ServiceContext services)
protected UmbracoHttpHandler(UmbracoContext umbracoContext, UmbracoHelper umbracoHelper, ServiceContext service, IProfilingLogger plogger)
{
if (umbracoContext == null) throw new ArgumentNullException(nameof(umbracoContext));
UmbracoContext = umbracoContext;
Umbraco = new UmbracoHelper(umbracoContext, services);
// TODO: inject somehow
Logger = Current.Logger;
ProfilingLogger = Current.ProfilingLogger;
Services = Current.Services;
Logger = plogger;
ProfilingLogger = plogger;
Services = service;
Umbraco = umbracoHelper;
}
public abstract void ProcessRequest(HttpContext context);

View File

@@ -21,15 +21,19 @@ namespace Umbraco.Web
{
private UrlHelper _url;
protected UmbracoWebService()
protected UmbracoWebService(IProfilingLogger profilingLogger, UmbracoContext umbracoContext, UmbracoHelper umbraco, ServiceContext services, IGlobalSettings globalSettings)
{
UmbracoContext = Current.UmbracoContext;
Umbraco = new UmbracoHelper(UmbracoContext, Current.Services);
Logger = profilingLogger;
ProfilingLogger = profilingLogger;
UmbracoContext = umbracoContext;
Umbraco = umbraco;
Services = services;
GlobalSettings = globalSettings;
}
Logger = Current.Logger;
ProfilingLogger = Current.ProfilingLogger;
Services = Current.Services;
GlobalSettings = Current.Configs.Global();
protected UmbracoWebService()
: this(Current.ProfilingLogger, Current.UmbracoContext, Current.UmbracoHelper, Current.Services, Current.Configs.Global())
{
}
/// <summary>

View File

@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Web.Http;
using Umbraco.Core;
using Umbraco.Web.Security;
using Umbraco.Core.Composing;
using Current = Umbraco.Web.Composing.Current;
namespace Umbraco.Web.WebApi
{
@@ -11,37 +13,6 @@ namespace Umbraco.Web.WebApi
/// </summary>
public sealed class MemberAuthorizeAttribute : AuthorizeAttribute
{
private readonly UmbracoContext _umbracoContext;
private UmbracoContext GetUmbracoContext()
{
return _umbracoContext ?? UmbracoContext.Current;
}
/// <summary>
/// THIS SHOULD BE ONLY USED FOR UNIT TESTS
/// </summary>
/// <param name="umbracoContext"></param>
public MemberAuthorizeAttribute(UmbracoContext umbracoContext)
{
if (umbracoContext == null) throw new ArgumentNullException("umbracoContext");
_umbracoContext = umbracoContext;
}
public MemberAuthorizeAttribute()
{
}
/// <summary>
/// Flag for whether to allow all site visitors or just authenticated members
/// </summary>
/// <remarks>
/// This is the same as applying the [AllowAnonymous] attribute
/// </remarks>
[Obsolete("Use [AllowAnonymous] instead")]
public bool AllowAll { get; set; }
/// <summary>
/// Comma delimited list of allowed member types
/// </summary>
@@ -69,17 +40,14 @@ namespace Umbraco.Web.WebApi
var members = new List<int>();
foreach (var s in AllowMembers.Split(','))
{
int id;
if (int.TryParse(s, out id))
if (int.TryParse(s, out var id))
{
members.Add(id);
}
}
return GetUmbracoContext().Security.IsMemberAuthorized(AllowAll,
AllowType.Split(','),
AllowGroup.Split(','),
members);
var helper = Current.Factory.GetInstance<MembershipHelper>();
return helper.IsMemberAuthorized(AllowType.Split(','), AllowGroup.Split(','), members);
}
}

View File

@@ -13,18 +13,12 @@ namespace Umbraco.Web.WebApi
/// </summary>
public abstract class UmbracoApiController : UmbracoApiControllerBase, IDiscoverable
{
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoApiController"/> with auto dependencies.
/// </summary>
/// <remarks>Dependencies are obtained from the <see cref="Current"/> service locator.</remarks>
protected UmbracoApiController()
{ }
{
}
/// <summary>
/// Initialize a new instance of the <see cref="UmbracoApiController"/> with all its dependencies.
/// </summary>
protected UmbracoApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{ }
protected UmbracoApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
}
}

View File

@@ -21,8 +21,6 @@ namespace Umbraco.Web.WebApi
[FeatureAuthorize]
public abstract class UmbracoApiControllerBase : ApiController
{
private UmbracoHelper _umbracoHelper;
// note: all Umbraco controllers have two constructors: one with all dependencies, which should be used,
// and one with auto dependencies, ie no dependencies - and then dependencies are automatically obtained
// here from the Current service locator - this is obviously evil, but it allows us to add new dependencies
@@ -40,14 +38,15 @@ namespace Umbraco.Web.WebApi
Current.Factory.GetInstance<ServiceContext>(),
Current.Factory.GetInstance<AppCaches>(),
Current.Factory.GetInstance<IProfilingLogger>(),
Current.Factory.GetInstance<IRuntimeState>()
Current.Factory.GetInstance<IRuntimeState>(),
Current.Factory.GetInstance<UmbracoHelper>()
)
{ }
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoApiControllerBase"/> class with all its dependencies.
/// </summary>
protected UmbracoApiControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
protected UmbracoApiControllerBase(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
{
GlobalSettings = globalSettings;
SqlContext = sqlContext;
@@ -56,6 +55,7 @@ namespace Umbraco.Web.WebApi
Logger = logger;
RuntimeState = runtimeState;
UmbracoContext = umbracoContext;
Umbraco = umbracoHelper;
}
/// <summary>
@@ -112,9 +112,8 @@ namespace Umbraco.Web.WebApi
/// <summary>
/// Gets the Umbraco helper.
/// </summary>
public UmbracoHelper Umbraco => _umbracoHelper
?? (_umbracoHelper = new UmbracoHelper(UmbracoContext, Services));
public UmbracoHelper Umbraco { get; }
/// <summary>
/// Gets the web security helper.
/// </summary>

View File

@@ -30,19 +30,13 @@ namespace Umbraco.Web.WebApi
{
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoAuthorizedApiController"/> with auto dependencies.
/// </summary>
/// <remarks>Dependencies are obtained from the <see cref="Current"/> service locator.</remarks>
protected UmbracoAuthorizedApiController()
{ }
{
}
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoAuthorizedApiController"/> class with all its dependencies.
/// </summary>
protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState)
{ }
protected UmbracoAuthorizedApiController(IGlobalSettings globalSettings, UmbracoContext umbracoContext, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
}
/// <summary>
/// Gets the user manager.