Merge branch 'netcore/feature/move-files-after-umbraco-context-abstractions' into netcore/feature/move-mappings-after-httpcontext

# Conflicts:
#	src/Umbraco.Web/Install/InstallHelper.cs
#	src/Umbraco.Web/Models/Mapping/CommonMapper.cs
This commit is contained in:
Bjarke Berg
2020-02-19 11:40:25 +01:00
47 changed files with 207 additions and 199 deletions
+1 -1
View File
@@ -25,7 +25,7 @@ dotnet_naming_rule.private_members_with_underscore.severity = suggestion
dotnet_naming_symbols.private_fields.applicable_kinds = field
dotnet_naming_symbols.private_fields.applicable_accessibilities = private
dotnet_naming_symbols.private_fields.required_modifiers = abstract,async,readonly,static # all except const
# dotnet_naming_symbols.private_fields.required_modifiers = abstract,async,readonly,static # all except const
dotnet_naming_style.prefix_underscore.capitalization = camel_case
dotnet_naming_style.prefix_underscore.required_prefix = _
@@ -29,8 +29,8 @@ namespace Umbraco.Core
/// </summary>
/// <param name="composition">The composition.</param>
/// <returns></returns>
public static DataEditorWithMediaPathCollectionBuilder DataEditorsWithMediaPath(this Composition composition)
=> composition.WithCollectionBuilder<DataEditorWithMediaPathCollectionBuilder>();
public static MediaUrlGeneratorCollectionBuilder MediaUrlGenerators(this Composition composition)
=> composition.WithCollectionBuilder<MediaUrlGeneratorCollectionBuilder>();
#endregion
}
@@ -4,7 +4,6 @@ using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Models.ContentEditing;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.ContentApps
@@ -12,18 +11,18 @@ namespace Umbraco.Web.ContentApps
public class ContentAppFactoryCollection : BuilderCollectionBase<IContentAppFactory>
{
private readonly ILogger _logger;
private readonly ICurrentUserAccessor _currentUserAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
public ContentAppFactoryCollection(IEnumerable<IContentAppFactory> items, ILogger logger, ICurrentUserAccessor currentUserAccessor)
public ContentAppFactoryCollection(IEnumerable<IContentAppFactory> items, ILogger logger, IUmbracoContextAccessor umbracoContextAccessor)
: base(items)
{
_logger = logger;
_currentUserAccessor = currentUserAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
}
private IEnumerable<IReadOnlyUserGroup> GetCurrentUserGroups()
{
var currentUser = _currentUserAccessor.TryGetCurrentUser();
var currentUser = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser;
return currentUser == null
? Enumerable.Empty<IReadOnlyUserGroup>()
: currentUser.Groups;
@@ -19,8 +19,8 @@ namespace Umbraco.Web.ContentApps
{
// get the logger just-in-time - see note below for manifest parser
var logger = factory.GetInstance<ILogger>();
var currentUserAccessor = factory.GetInstance<ICurrentUserAccessor>();
return new ContentAppFactoryCollection(CreateItems(factory), logger, currentUserAccessor);
var umbracoContextAccessor = factory.GetInstance<IUmbracoContextAccessor>();
return new ContentAppFactoryCollection(CreateItems(factory), logger, umbracoContextAccessor);
}
protected override IEnumerable<IContentAppFactory> CreateItems(IFactory factory)
@@ -1,21 +0,0 @@
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Must be implemented by property editors that store media and return media paths
/// </summary>
/// <remarks>
/// Currently there are only 2x core editors that do this: upload and image cropper.
/// It would be possible for developers to know implement their own media property editors whereas previously this was not possible.
/// </remarks>
public interface IDataEditorWithMediaPath
{
string Alias { get; }
/// <summary>
/// Returns the media path for the value stored for a property
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
string GetMediaPath(object value);
}
}
@@ -0,0 +1,18 @@
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Used to generate paths to media items for a specified property editor alias
/// </summary>
public interface IMediaUrlGenerator
{
/// <summary>
/// Tries to get a media path for a given property editor alias
/// </summary>
/// <param name="alias">The property editor alias</param>
/// <param name="value">The value of the property</param>
/// <returns>
/// True if a media path was returned
/// </returns>
bool TryGetMediaPath(string alias, object value, out string mediaPath);
}
}
@@ -1,13 +0,0 @@
using Umbraco.Core.Models.Membership;
namespace Umbraco.Core.Models.Identity
{
public interface ICurrentUserAccessor
{
/// <summary>
/// Returns the current user or null if no user is currently authenticated.
/// </summary>
/// <returns>The current user or null</returns>
IUser TryGetCurrentUser();
}
}
@@ -1,21 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Composing;
namespace Umbraco.Core.PropertyEditors
{
public class DataEditorWithMediaPathCollection : BuilderCollectionBase<IDataEditorWithMediaPath>
{
public DataEditorWithMediaPathCollection(IEnumerable<IDataEditorWithMediaPath> items) : base(items)
{
}
public bool TryGet(string alias, out IDataEditorWithMediaPath editor)
{
editor = this.FirstOrDefault(x => x.Alias == alias);
return editor != null;
}
}
}
@@ -1,9 +0,0 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.PropertyEditors
{
public class DataEditorWithMediaPathCollectionBuilder : LazyCollectionBuilderBase<DataEditorWithMediaPathCollectionBuilder, DataEditorWithMediaPathCollection, IDataEditorWithMediaPath>
{
protected override DataEditorWithMediaPathCollectionBuilder This => this;
}
}
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using Umbraco.Core.Composing;
namespace Umbraco.Core.PropertyEditors
{
public class MediaUrlGeneratorCollection : BuilderCollectionBase<IMediaUrlGenerator>
{
public MediaUrlGeneratorCollection(IEnumerable<IMediaUrlGenerator> items) : base(items)
{
}
public bool TryGetMediaPath(string alias, object value, out string mediaPath)
{
foreach(var generator in this)
{
if (generator.TryGetMediaPath(alias, value, out var mp))
{
mediaPath = mp;
return true;
}
}
mediaPath = null;
return false;
}
}
}
@@ -0,0 +1,9 @@
using Umbraco.Core.Composing;
namespace Umbraco.Core.PropertyEditors
{
public class MediaUrlGeneratorCollectionBuilder : LazyCollectionBuilderBase<MediaUrlGeneratorCollectionBuilder, MediaUrlGeneratorCollection, IMediaUrlGenerator>
{
protected override MediaUrlGeneratorCollectionBuilder This => this;
}
}
@@ -10,11 +10,11 @@ namespace Umbraco.Web.Routing
public class DefaultMediaUrlProvider : IMediaUrlProvider
{
private readonly UriUtility _uriUtility;
private readonly DataEditorWithMediaPathCollection _dataEditors;
private readonly MediaUrlGeneratorCollection _mediaPathGenerators;
public DefaultMediaUrlProvider(DataEditorWithMediaPathCollection dataEditors, UriUtility uriUtility)
public DefaultMediaUrlProvider(MediaUrlGeneratorCollection mediaPathGenerators, UriUtility uriUtility)
{
_dataEditors = dataEditors ?? throw new ArgumentNullException(nameof(dataEditors));
_mediaPathGenerators = mediaPathGenerators ?? throw new ArgumentNullException(nameof(mediaPathGenerators));
_uriUtility = uriUtility;
}
@@ -32,24 +32,23 @@ namespace Umbraco.Web.Routing
}
var propType = prop.PropertyType;
string path = null;
if (_dataEditors.TryGet(propType.EditorAlias, out var dataEditor))
if (_mediaPathGenerators.TryGetMediaPath(propType.EditorAlias, value, out var path))
{
path = dataEditor.GetMediaPath(value);
var url = AssembleUrl(path, current, mode);
return UrlInfo.Url(url.ToString(), culture);
}
var url = AssembleUrl(path, current, mode);
return url == null ? null : UrlInfo.Url(url.ToString(), culture);
return null;
}
private Uri AssembleUrl(string path, Uri current, UrlMode mode)
{
if (string.IsNullOrEmpty(path))
return null;
if (string.IsNullOrWhiteSpace(path))
throw new ArgumentException($"{nameof(path)} cannot be null or whitespace", nameof(path));
// the stored path is absolute so we just return it as is
if(Uri.IsWellFormedUriString(path, UriKind.Absolute))
if (Uri.IsWellFormedUriString(path, UriKind.Absolute))
return new Uri(path);
Uri uri;
@@ -14,22 +14,24 @@ namespace Umbraco.Web
/// </remarks>
public class UmbracoContextReference : IDisposable //fixme - should we inherit from DisposableObjectSlim?
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private bool _disposed;
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoContextReference"/> class.
/// </summary>
internal UmbracoContextReference(bool isRoot, IUmbracoContext umbracoContext)
internal UmbracoContextReference(IUmbracoContext umbracoContext, bool isRoot, IUmbracoContextAccessor umbracoContextAccessor)
{
IsRoot = isRoot;
UmbracoContext = umbracoContext;
_umbracoContextAccessor = umbracoContextAccessor;
}
/// <summary>
/// Gets the <see cref="UmbracoContext"/>.
/// </summary>
public IUmbracoContext UmbracoContext { get; private set; }
public IUmbracoContext UmbracoContext { get; }
/// <summary>
/// Gets a value indicating whether the reference is a root reference.
@@ -49,7 +51,7 @@ namespace Umbraco.Web
if (IsRoot)
{
UmbracoContext.Dispose();
UmbracoContext = null;
_umbracoContextAccessor.UmbracoContext = null;
}
GC.SuppressFinalize(this);
@@ -9,6 +9,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Persistence;
using Umbraco.Core.Services;
using Umbraco.Web;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Examine
@@ -17,19 +18,19 @@ namespace Umbraco.Examine
{
private readonly IExamineManager _examineManager;
private readonly ILocalizationService _languageService;
private readonly ICurrentUserAccessor _currentUserAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IEntityService _entityService;
private readonly IUmbracoTreeSearcherFields _treeSearcherFields;
public BackOfficeExamineSearcher(IExamineManager examineManager,
ILocalizationService languageService,
ICurrentUserAccessor currentUserAccessor,
IUmbracoContextAccessor umbracoContextAccessor,
IEntityService entityService,
IUmbracoTreeSearcherFields treeSearcherFields)
{
_examineManager = examineManager;
_languageService = languageService;
_currentUserAccessor = currentUserAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_entityService = entityService;
_treeSearcherFields = treeSearcherFields;
}
@@ -48,7 +49,7 @@ namespace Umbraco.Examine
query = "\"" + g.ToString() + "\"";
}
var currentUser = _currentUserAccessor.TryGetCurrentUser();
var currentUser = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser;
switch (entityType)
{
@@ -148,13 +148,12 @@ namespace Umbraco.Web.Compose
/// </summary>
public sealed class Notifier
{
private readonly ICurrentUserAccessor _currentUserAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly IRuntimeState _runtimeState;
private readonly INotificationService _notificationService;
private readonly IUserService _userService;
private readonly ILocalizedTextService _textService;
private readonly IGlobalSettings _globalSettings;
private readonly IContentSection _contentConfig;
private readonly ILogger _logger;
/// <summary>
@@ -167,21 +166,20 @@ namespace Umbraco.Web.Compose
/// <param name="globalSettings"></param>
/// <param name="contentConfig"></param>
/// <param name="logger"></param>
public Notifier(ICurrentUserAccessor currentUserAccessor, IRuntimeState runtimeState, INotificationService notificationService, IUserService userService, ILocalizedTextService textService, IGlobalSettings globalSettings, IContentSection contentConfig, ILogger logger)
public Notifier(IUmbracoContextAccessor umbracoContextAccessor, IRuntimeState runtimeState, INotificationService notificationService, IUserService userService, ILocalizedTextService textService, IGlobalSettings globalSettings, ILogger logger)
{
_currentUserAccessor = currentUserAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
_runtimeState = runtimeState;
_notificationService = notificationService;
_userService = userService;
_textService = textService;
_globalSettings = globalSettings;
_contentConfig = contentConfig;
_logger = logger;
}
public void Notify(IAction action, params IContent[] entities)
{
var user = _currentUserAccessor.TryGetCurrentUser();
var user = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser;
//if there is no current user, then use the admin
if (user == null)
@@ -1,7 +1,5 @@
using System.Linq;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Models
@@ -11,17 +9,15 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets the url of a media item.
/// </summary>
public static string GetUrl(this IMedia media, string propertyAlias, ILogger logger, PropertyEditorCollection propertyEditors)
public static string GetUrl(this IMedia media, string propertyAlias, MediaUrlGeneratorCollection mediaUrlGenerators)
{
if (!media.Properties.TryGetValue(propertyAlias, out var property))
return string.Empty;
if (propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out var editor)
&& editor is IDataEditorWithMediaPath dataEditor)
{
// TODO: would need to be adjusted to variations, when media become variants
var value = property.GetValue();
return dataEditor.GetMediaPath(value);
// TODO: would need to be adjusted to variations, when media become variants
if (mediaUrlGenerators.TryGetMediaPath(property.PropertyType.PropertyEditorAlias, property.GetValue(), out var mediaUrl))
{
return mediaUrl;
}
// Without knowing what it is, just adding a string here might not be very nice
@@ -31,10 +27,10 @@ namespace Umbraco.Core.Models
/// <summary>
/// Gets the urls of a media item.
/// </summary>
public static string[] GetUrls(this IMedia media, IContentSection contentSection, ILogger logger, PropertyEditorCollection propertyEditors)
public static string[] GetUrls(this IMedia media, IContentSection contentSection, MediaUrlGeneratorCollection mediaUrlGenerators)
{
return contentSection.ImageAutoFillProperties
.Select(field => media.GetUrl(field.Alias, logger, propertyEditors))
.Select(field => media.GetUrl(field.Alias, mediaUrlGenerators))
.Where(link => string.IsNullOrWhiteSpace(link) == false)
.ToArray();
}
@@ -185,7 +185,7 @@ namespace Umbraco.Core.Persistence.Factories
/// <summary>
/// Builds a dto from an IMedia item.
/// </summary>
public static MediaDto BuildDto(PropertyEditorCollection propertyEditors, IMedia entity)
public static MediaDto BuildDto(MediaUrlGeneratorCollection mediaUrlGenerators, IMedia entity)
{
var contentDto = BuildContentDto(entity, Constants.ObjectTypes.Media);
@@ -193,7 +193,7 @@ namespace Umbraco.Core.Persistence.Factories
{
NodeId = entity.Id,
ContentDto = contentDto,
MediaVersionDto = BuildMediaVersionDto(propertyEditors, entity, contentDto)
MediaVersionDto = BuildMediaVersionDto(mediaUrlGenerators, entity, contentDto)
};
return dto;
@@ -287,7 +287,7 @@ namespace Umbraco.Core.Persistence.Factories
return dto;
}
private static MediaVersionDto BuildMediaVersionDto(PropertyEditorCollection propertyEditors, IMedia entity, ContentDto contentDto)
private static MediaVersionDto BuildMediaVersionDto(MediaUrlGeneratorCollection mediaUrlGenerators, IMedia entity, ContentDto contentDto)
{
// try to get a path from the string being stored for media
// TODO: only considering umbracoFile
@@ -295,11 +295,9 @@ namespace Umbraco.Core.Persistence.Factories
string path = null;
if (entity.Properties.TryGetValue(Constants.Conventions.Media.File, out var property)
&& propertyEditors.TryGet(property.PropertyType.PropertyEditorAlias, out var editor)
&& editor is IDataEditorWithMediaPath dataEditor)
&& mediaUrlGenerators.TryGetMediaPath(property.PropertyType.PropertyEditorAlias, property.GetValue(), out var mediaPath))
{
var value = property.GetValue();
path = dataEditor.GetMediaPath(value);
path = mediaPath;
}
var dto = new MediaVersionDto
@@ -25,6 +25,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
{
private readonly IMediaTypeRepository _mediaTypeRepository;
private readonly ITagRepository _tagRepository;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly MediaByGuidReadRepository _mediaByGuidReadRepository;
public MediaRepository(
@@ -37,12 +38,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
IRelationRepository relationRepository,
IRelationTypeRepository relationTypeRepository,
Lazy<PropertyEditorCollection> propertyEditorCollection,
MediaUrlGeneratorCollection mediaUrlGenerators,
DataValueReferenceFactoryCollection dataValueReferenceFactories,
IDataTypeService dataTypeService)
: base(scopeAccessor, cache, logger, languageRepository, relationRepository, relationTypeRepository, propertyEditorCollection, dataValueReferenceFactories, dataTypeService)
{
_mediaTypeRepository = mediaTypeRepository ?? throw new ArgumentNullException(nameof(mediaTypeRepository));
_tagRepository = tagRepository ?? throw new ArgumentNullException(nameof(tagRepository));
_mediaUrlGenerators = mediaUrlGenerators;
_mediaByGuidReadRepository = new MediaByGuidReadRepository(this, scopeAccessor, cache, logger);
}
@@ -239,7 +242,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
entity.SanitizeEntityPropertiesForXmlStorage();
// create the dto
var dto = ContentBaseFactory.BuildDto(PropertyEditors, entity);
var dto = ContentBaseFactory.BuildDto(_mediaUrlGenerators, entity);
// derive path and level from parent
var parent = GetParentNodeDto(entity.ParentId);
@@ -330,7 +333,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
// create the dto
var dto = ContentBaseFactory.BuildDto(PropertyEditors, entity);
var dto = ContentBaseFactory.BuildDto(_mediaUrlGenerators, entity);
// update the node dto
var nodeDto = dto.ContentDto.NodeDto;
@@ -11,6 +11,9 @@ namespace Umbraco.Core.PropertyEditors
: base(items)
{ }
// TODO: We could further reduce circular dependencies with PropertyEditorCollection by not having IDataValueReference implemented
// by property editors and instead just use the already built in IDataValueReferenceFactory and/or refactor that into a more normal collection
public IEnumerable<UmbracoEntityReference> GetAllReferences(IPropertyCollection properties, PropertyEditorCollection propertyEditors)
{
var trackedRelations = new List<UmbracoEntityReference>();
@@ -19,7 +19,7 @@ namespace Umbraco.Web.PropertyEditors
"fileupload",
Group = Constants.PropertyEditors.Groups.Media,
Icon = "icon-download-alt")]
public class FileUploadPropertyEditor : DataEditor, IDataEditorWithMediaPath
public class FileUploadPropertyEditor : DataEditor, IMediaUrlGenerator
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSection _contentSection;
@@ -52,7 +52,16 @@ namespace Umbraco.Web.PropertyEditors
return editor;
}
public string GetMediaPath(object value) => value?.ToString();
public bool TryGetMediaPath(string alias, object value, out string mediaPath)
{
if (alias == Alias)
{
mediaPath = value?.ToString();
return true;
}
mediaPath = null;
return false;
}
/// <summary>
/// Gets a value indicating whether a property is an upload field.
@@ -26,7 +26,7 @@ namespace Umbraco.Web.PropertyEditors
HideLabel = false,
Group = Constants.PropertyEditors.Groups.Media,
Icon = "icon-crop")]
public class ImageCropperPropertyEditor : DataEditor, IDataEditorWithMediaPath
public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSection _contentSettings;
@@ -53,7 +53,16 @@ namespace Umbraco.Web.PropertyEditors
_autoFillProperties = new UploadAutoFillProperties(_mediaFileSystem, logger, _contentSettings);
}
public string GetMediaPath(object value) => GetFileSrcFromPropertyValue(value, out _, false);
public bool TryGetMediaPath(string alias, object value, out string mediaPath)
{
if (alias == Alias)
{
mediaPath = GetFileSrcFromPropertyValue(value, out _, false);
return true;
}
mediaPath = null;
return false;
}
/// <summary>
/// Creates the corresponding property value editor.
@@ -85,7 +85,7 @@ namespace Umbraco.Core.Runtime
composition.DataEditors()
.Add(() => composition.TypeLoader.GetDataEditors());
composition.DataEditorsWithMediaPath()
composition.MediaUrlGenerators()
.Add<FileUploadPropertyEditor>()
.Add<ImageCropperPropertyEditor>();
@@ -44,8 +44,9 @@ namespace Umbraco.Tests.Persistence.Repositories
var entityRepository = new EntityRepository(scopeAccessor);
var relationRepository = new RelationRepository(scopeAccessor, Logger, relationTypeRepository, entityRepository);
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty<IMediaUrlGenerator>());
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService);
var repository = new MediaRepository(scopeAccessor, appCaches, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService);
return repository;
}
@@ -981,8 +981,9 @@ namespace Umbraco.Tests.Persistence.Repositories
var entityRepository = new EntityRepository(accessor);
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty<IMediaUrlGenerator>());
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService);
var repository = new MediaRepository(accessor, AppCaches.Disabled, Logger, mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService);
return repository;
}
}
@@ -36,8 +36,9 @@ namespace Umbraco.Tests.Persistence.Repositories
var entityRepository = new EntityRepository(accessor);
var relationRepository = new RelationRepository(accessor, Logger, relationTypeRepository, entityRepository);
var propertyEditors = new Lazy<PropertyEditorCollection>(() => new PropertyEditorCollection(new DataEditorCollection(Enumerable.Empty<IDataEditor>())));
var mediaUrlGenerators = new MediaUrlGeneratorCollection(Enumerable.Empty<IMediaUrlGenerator>());
var dataValueReferences = new DataValueReferenceFactoryCollection(Enumerable.Empty<IDataValueReferenceFactory>());
var repository = new MediaRepository(accessor, AppCaches, Mock.Of<ILogger>(), mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, dataValueReferences, DataTypeService);
var repository = new MediaRepository(accessor, AppCaches, Mock.Of<ILogger>(), mediaTypeRepository, tagRepository, Mock.Of<ILanguageRepository>(), relationRepository, relationTypeRepository, propertyEditors, mediaUrlGenerators, dataValueReferences, DataTypeService);
return repository;
}
@@ -38,7 +38,7 @@ namespace Umbraco.Tests.Routing
var dataTypeService = Mock.Of<IDataTypeService>();
var umbracoSettingsSection = TestObjects.GetUmbracoSettings();
var propertyEditors = new DataEditorWithMediaPathCollection(new IDataEditorWithMediaPath[]
var propertyEditors = new MediaUrlGeneratorCollection(new IMediaUrlGenerator[]
{
new FileUploadPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, LocalizedTextService, ShortStringHelper, umbracoSettingsSection),
new ImageCropperPropertyEditor(logger, mediaFileSystemMock, contentSection, dataTypeService, LocalizationService, IOHelper, ShortStringHelper, LocalizedTextService, umbracoSettingsSection),
+3 -1
View File
@@ -201,7 +201,6 @@ namespace Umbraco.Tests.Testing
Composition.RegisterUnique(backOfficeInfo);
Composition.RegisterUnique(ipResolver);
Composition.RegisterUnique<IPasswordHasher, AspNetPasswordHasher>();
Composition.RegisterUnique<ICurrentUserAccessor, CurrentUserAccessor>();
Composition.RegisterUnique(TestHelper.ShortStringHelper);
@@ -338,6 +337,9 @@ namespace Umbraco.Tests.Testing
// manifest
Composition.ManifestValueValidators();
Composition.ManifestFilters();
Composition.MediaUrlGenerators()
.Add<FileUploadPropertyEditor>()
.Add<ImageCropperPropertyEditor>();
}
@@ -11,12 +11,7 @@ namespace Umbraco.Web
{
var httpContext = System.Web.HttpContext.Current;
if (httpContext is null)
{
throw new InvalidOperationException("HttpContext is not available");
}
return new HttpContextWrapper(httpContext);
return httpContext is null ? null : new HttpContextWrapper(httpContext);
}
set
{
@@ -378,7 +378,7 @@ namespace Umbraco.Web.Editors
"externalLogins", new Dictionary<string, object>
{
{
"providers", _httpContextAccessor.HttpContext.GetOwinContext().Authentication.GetExternalAuthenticationTypes()
"providers", _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().Authentication.GetExternalAuthenticationTypes()
.Where(p => p.Properties.ContainsKey("UmbracoBackOffice"))
.Select(p => new
{
@@ -465,7 +465,7 @@ namespace Umbraco.Web.Editors
app.Add("cacheBuster", $"{version}.{_runtimeState.Level}.{ClientDependencySettings.Instance.Version}".GenerateHash());
//useful for dealing with virtual paths on the client side when hosted in virtual directories especially
app.Add("applicationPath", _httpContextAccessor.HttpContext.Request.ApplicationPath.EnsureEndsWith('/'));
app.Add("applicationPath", _httpContextAccessor.GetRequiredHttpContext().Request.ApplicationPath.EnsureEndsWith('/'));
//add the server's GMT time offset in minutes
app.Add("serverTimeOffset", Convert.ToInt32(DateTimeOffset.Now.Offset.TotalMinutes));
+1 -4
View File
@@ -27,7 +27,6 @@ namespace Umbraco.Web.Editors
private readonly TourFilterCollection _filters;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
private readonly IIOHelper _ioHelper;
private readonly ICurrentUserAccessor _currentUserAccessor;
public TourController(
IGlobalSettings globalSettings,
@@ -43,14 +42,12 @@ namespace Umbraco.Web.Editors
TourFilterCollection filters,
IUmbracoSettingsSection umbracoSettingsSection,
IIOHelper ioHelper,
ICurrentUserAccessor currentUserAccessor,
IPublishedUrlProvider publishedUrlProvider)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_filters = filters;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_ioHelper = ioHelper;
_currentUserAccessor = currentUserAccessor;
}
public IEnumerable<BackOfficeTourFile> GetTours()
@@ -60,7 +57,7 @@ namespace Umbraco.Web.Editors
if (_umbracoSettingsSection.BackOffice.Tours.EnableTours == false)
return result;
var user = _currentUserAccessor.TryGetCurrentUser();
var user = UmbracoContext.Security.CurrentUser;
if (user == null)
return result;
@@ -67,7 +67,7 @@ namespace Umbraco.Web
var htmlBadge =
String.Format(umbracoSettingsSection.Content.PreviewBadge,
ioHelper.ResolveUrl(globalSettings.UmbracoPath),
WebUtility.UrlEncode(httpContextAccessor.HttpContext.Request.Path),
WebUtility.UrlEncode(httpContextAccessor.GetRequiredHttpContext().Request.Path),
Current.UmbracoContext.PublishedRequest.PublishedContent.Id);
return new MvcHtmlString(htmlBadge);
}
@@ -0,0 +1,17 @@
using System.IO;
using System.Web;
namespace Umbraco.Web
{
public static class HttpContextAccessorExtensions
{
public static HttpContextBase GetRequiredHttpContext(this IHttpContextAccessor httpContextAccessor)
{
var httpContext = httpContextAccessor.HttpContext;
if(httpContext is null) throw new IOException("HttpContext is null");
return httpContext;
}
}
}
+1 -1
View File
@@ -48,7 +48,7 @@ namespace Umbraco.Web.Install
public void InstallStatus(bool isCompleted, string errorMsg)
{
var httpContext = _httpContextAccessor.HttpContext;
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
try
{
var userAgent = httpContext.Request.UserAgent;
@@ -56,7 +56,7 @@ namespace Umbraco.Web.Install.InstallSteps
throw new InvalidOperationException("Could not find the super user!");
}
var userManager = _httpContextAccessor.HttpContext.GetOwinContext().GetBackOfficeUserManager();
var userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager();
var membershipUser = await userManager.FindByIdAsync(Constants.Security.SuperUserId);
if (membershipUser == null)
{
@@ -34,7 +34,7 @@ namespace Umbraco.Web.Install.InstallSteps
InstallBusinessLogic(packageId);
UmbracoApplication.Restart(_httContextAccessor.HttpContext);
UmbracoApplication.Restart(_httContextAccessor.GetRequiredHttpContext());
return Task.FromResult<InstallSetupResult>(null);
}
@@ -24,17 +24,17 @@ namespace Umbraco.Web.Models.Mapping
private readonly ContentAppFactoryCollection _contentAppDefinitions;
private readonly ILocalizedTextService _localizedTextService;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ICurrentUserAccessor _currentUserAccessor;
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider,
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService, IHttpContextAccessor httpContextAccessor, ICurrentUserAccessor currentUserAccessor)
public CommonMapper(IUserService userService, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider, IUmbracoContextAccessor umbracoContextAccessor,
ContentAppFactoryCollection contentAppDefinitions, ILocalizedTextService localizedTextService, IHttpContextAccessor httpContextAccessor)
{
_userService = userService;
_contentTypeBaseServiceProvider = contentTypeBaseServiceProvider;
_contentAppDefinitions = contentAppDefinitions;
_localizedTextService = localizedTextService;
_httpContextAccessor = httpContextAccessor;
_currentUserAccessor = currentUserAccessor;
_umbracoContextAccessor = umbracoContextAccessor;
}
public UserProfile GetOwner(IContentBase source, MapperContext context)
@@ -52,7 +52,7 @@ namespace Umbraco.Web.Models.Mapping
public ContentTypeBasic GetContentType(IContentBase source, MapperContext context)
{
var user = _currentUserAccessor.TryGetCurrentUser();
var user = _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser;
if (user?.AllowedSections.Any(x => x.Equals(Constants.Applications.Settings)) ?? false)
{
var contentType = _contentTypeBaseServiceProvider.GetContentTypeOf(source);
@@ -18,21 +18,19 @@ namespace Umbraco.Web.Models.Mapping
public class MediaMapDefinition : IMapDefinition
{
private readonly CommonMapper _commonMapper;
private readonly ILogger _logger;
private readonly IMediaService _mediaService;
private readonly IMediaTypeService _mediaTypeService;
private readonly PropertyEditorCollection _propertyEditorCollection;
private readonly MediaUrlGeneratorCollection _mediaUrlGenerators;
private readonly TabsAndPropertiesMapper<IMedia> _tabsAndPropertiesMapper;
private readonly IUmbracoSettingsSection _umbracoSettingsSection;
public MediaMapDefinition(ICultureDictionary cultureDictionary, ILogger logger, CommonMapper commonMapper, IMediaService mediaService, IMediaTypeService mediaTypeService,
ILocalizedTextService localizedTextService, PropertyEditorCollection propertyEditorCollection, IUmbracoSettingsSection umbracoSettingsSection, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider)
public MediaMapDefinition(ICultureDictionary cultureDictionary, CommonMapper commonMapper, IMediaService mediaService, IMediaTypeService mediaTypeService,
ILocalizedTextService localizedTextService, MediaUrlGeneratorCollection mediaUrlGenerators, IUmbracoSettingsSection umbracoSettingsSection, IContentTypeBaseServiceProvider contentTypeBaseServiceProvider)
{
_logger = logger;
_commonMapper = commonMapper;
_mediaService = mediaService;
_mediaTypeService = mediaTypeService;
_propertyEditorCollection = propertyEditorCollection;
_mediaUrlGenerators = mediaUrlGenerators;
_umbracoSettingsSection = umbracoSettingsSection ?? throw new ArgumentNullException(nameof(umbracoSettingsSection));
_tabsAndPropertiesMapper = new TabsAndPropertiesMapper<IMedia>(cultureDictionary, localizedTextService, contentTypeBaseServiceProvider);
@@ -64,7 +62,7 @@ namespace Umbraco.Web.Models.Mapping
target.Id = source.Id;
target.IsChildOfListView = DetermineIsChildOfListView(source);
target.Key = source.Key;
target.MediaLink = string.Join(",", source.GetUrls(_umbracoSettingsSection.Content, _logger, _propertyEditorCollection));
target.MediaLink = string.Join(",", source.GetUrls(_umbracoSettingsSection.Content, _mediaUrlGenerators));
target.Name = source.Name;
target.Owner = _commonMapper.GetOwner(source, context);
target.ParentId = source.ParentId;
@@ -56,11 +56,12 @@ namespace Umbraco.Web.Routing
if (node != null)
{
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
//if we have a node, check if we have a culture in the query string
if (_httpContextAccessor.HttpContext.Request.QueryString.ContainsKey("culture"))
if (httpContext.Request.QueryString.ContainsKey("culture"))
{
//we're assuming it will match a culture, if an invalid one is passed in, an exception will throw (there is no TryGetCultureInfo method), i think this is ok though
frequest.Culture = CultureInfo.GetCultureInfo(_httpContextAccessor.HttpContext.Request.QueryString["culture"]);
frequest.Culture = CultureInfo.GetCultureInfo(httpContext.Request.QueryString["culture"]);
}
frequest.PublishedContent = node;
@@ -19,7 +19,7 @@
public bool TryFindContent(IPublishedRequest frequest)
{
int pageId;
if (int.TryParse(_httpContextAccessor.HttpContext.Request["umbPageID"], out pageId))
if (int.TryParse(_httpContextAccessor.GetRequiredHttpContext().Request["umbPageID"], out pageId))
{
var doc = frequest.UmbracoContext.Content.GetById(pageId);
+1 -1
View File
@@ -637,7 +637,7 @@ namespace Umbraco.Web.Routing
var useAltTemplate = request.IsInitialPublishedContent
|| (_webRoutingSection.InternalRedirectPreservesTemplate && request.IsInternalRedirectPublishedContent);
var altTemplate = useAltTemplate
? _httpContextAccessor.HttpContext.Request[Constants.Conventions.Url.AltTemplate]
? _httpContextAccessor.GetRequiredHttpContext().Request[Constants.Conventions.Url.AltTemplate]
: null;
if (string.IsNullOrWhiteSpace(altTemplate))
@@ -68,7 +68,6 @@ namespace Umbraco.Web.Runtime
composition.Register<IHostingEnvironment, AspNetHostingEnvironment>();
composition.Register<IBackOfficeInfo, AspNetBackOfficeInfo>();
composition.Register<IPasswordHasher, AspNetPasswordHasher>();
composition.Register<ICurrentUserAccessor, CurrentUserAccessor>();
composition.Register<IFilePermissionHelper, FilePermissionHelper>(Lifetime.Singleton);
composition.RegisterUnique<IHttpContextAccessor, AspNetHttpContextAccessor>(); // required for hybrid accessors
@@ -1,21 +0,0 @@
using Umbraco.Core.Models.Identity;
using Umbraco.Core.Models.Membership;
namespace Umbraco.Web.Security
{
internal class CurrentUserAccessor : ICurrentUserAccessor
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
public CurrentUserAccessor(IUmbracoContextAccessor umbracoContextAccessor)
{
_umbracoContextAccessor = umbracoContextAccessor;
}
/// <inheritdoc/>
public IUser TryGetCurrentUser()
{
return _umbracoContextAccessor.UmbracoContext?.Security?.CurrentUser;
}
}
}
+14 -12
View File
@@ -61,7 +61,7 @@ namespace Umbraco.Web.Security
{
if (_signInManager == null)
{
var mgr = _httpContextAccessor.HttpContext.GetOwinContext().Get<BackOfficeSignInManager>();
var mgr = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().Get<BackOfficeSignInManager>();
if (mgr == null)
{
throw new NullReferenceException("Could not resolve an instance of " + typeof(BackOfficeSignInManager) + " from the " + typeof(IOwinContext));
@@ -74,12 +74,13 @@ namespace Umbraco.Web.Security
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
protected BackOfficeUserManager<BackOfficeIdentityUser> UserManager
=> _userManager ?? (_userManager = _httpContextAccessor.HttpContext.GetOwinContext().GetBackOfficeUserManager());
=> _userManager ?? (_userManager = _httpContextAccessor.GetRequiredHttpContext().GetOwinContext().GetBackOfficeUserManager());
[Obsolete("This needs to be removed, ASP.NET Identity should always be used for this operation, this is currently only used in the installer which needs to be updated")]
public double PerformLogin(int userId)
{
var owinCtx = _httpContextAccessor.HttpContext.GetOwinContext();
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
var owinCtx = httpContext.GetOwinContext();
//ensure it's done for owin too
owinCtx.Authentication.SignOut(Constants.Security.BackOfficeExternalAuthenticationType);
@@ -87,7 +88,7 @@ namespace Umbraco.Web.Security
SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false).Wait();
_httpContextAccessor.HttpContext.SetPrincipalForRequest(owinCtx.Request.User);
httpContext.SetPrincipalForRequest(owinCtx.Request.User);
return TimeSpan.FromMinutes(_globalSettings.TimeOutInMinutes).TotalSeconds;
}
@@ -95,8 +96,9 @@ namespace Umbraco.Web.Security
[Obsolete("This needs to be removed, ASP.NET Identity should always be used for this operation, this is currently only used in the installer which needs to be updated")]
public void ClearCurrentLogin()
{
_httpContextAccessor.HttpContext.UmbracoLogout();
_httpContextAccessor.HttpContext.GetOwinContext().Authentication.SignOut(
var httpContext = _httpContextAccessor.GetRequiredHttpContext();
httpContext.UmbracoLogout();
httpContext.GetOwinContext().Authentication.SignOut(
Core.Constants.Security.BackOfficeAuthenticationType,
Core.Constants.Security.BackOfficeExternalAuthenticationType);
}
@@ -108,7 +110,7 @@ namespace Umbraco.Web.Security
/// <returns></returns>
public Attempt<int> GetUserId()
{
var identity = _httpContextAccessor.HttpContext.GetCurrentIdentity(false);
var identity = _httpContextAccessor.GetRequiredHttpContext().GetCurrentIdentity(false);
return identity == null ? Attempt.Fail<int>() : Attempt.Succeed(Convert.ToInt32(identity.Id));
}
@@ -143,7 +145,7 @@ namespace Umbraco.Web.Security
var user = CurrentUser;
// Check for console access
if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContextAccessor.HttpContext, _globalSettings, _ioHelper)))
if (user == null || (requiresApproval && user.IsApproved == false) || (user.IsLockedOut && RequestIsInUmbracoApplication(_httpContextAccessor, _globalSettings, _ioHelper)))
{
if (throwExceptions) throw new ArgumentException("You have no privileges to the umbraco console. Please contact your administrator");
return ValidateRequestAttempt.FailedNoPrivileges;
@@ -152,9 +154,9 @@ namespace Umbraco.Web.Security
}
private static bool RequestIsInUmbracoApplication(HttpContextBase context, IGlobalSettings globalSettings, IIOHelper ioHelper)
private static bool RequestIsInUmbracoApplication(IHttpContextAccessor httpContextAccessor, IGlobalSettings globalSettings, IIOHelper ioHelper)
{
return context.Request.Path.ToLower().IndexOf(ioHelper.ResolveUrl(globalSettings.UmbracoPath).ToLower(), StringComparison.Ordinal) > -1;
return httpContextAccessor.GetRequiredHttpContext().Request.Path.ToLower().IndexOf(ioHelper.ResolveUrl(globalSettings.UmbracoPath).ToLower(), StringComparison.Ordinal) > -1;
}
/// <summary>
@@ -165,7 +167,7 @@ namespace Umbraco.Web.Security
public ValidateRequestAttempt AuthorizeRequest(bool throwExceptions = false)
{
// check for secure connection
if (_globalSettings.UseHttps && _httpContextAccessor.HttpContext.Request.IsSecureConnection == false)
if (_globalSettings.UseHttps && _httpContextAccessor.GetRequiredHttpContext().Request.IsSecureConnection == false)
{
if (throwExceptions) throw new SecurityException("This installation requires a secure connection (via SSL). Please update the URL to include https://");
return ValidateRequestAttempt.FailedNoSsl;
@@ -191,7 +193,7 @@ namespace Umbraco.Web.Security
public bool IsAuthenticated()
{
var httpContext = _httpContextAccessor.HttpContext;
return httpContext.User != null && httpContext.User.Identity.IsAuthenticated && httpContext.GetCurrentIdentity(false) != null;
return httpContext?.User != null && httpContext.User.Identity.IsAuthenticated && httpContext.GetCurrentIdentity(false) != null;
}
}
@@ -127,7 +127,7 @@ namespace Umbraco.Web.Templates
//var queryString = _umbracoContext.HttpContext.Request.QueryString.AllKeys
// .ToDictionary(key => key, key => context.Request.QueryString[key]);
var requestContext = new RequestContext(_httpContextAccessor.HttpContext, new RouteData()
var requestContext = new RequestContext(_httpContextAccessor.GetRequiredHttpContext(), new RouteData()
{
Route = RouteTable.Routes["Umbraco_default"]
});
+7
View File
@@ -149,6 +149,9 @@
<Compile Include="Editors\MacrosController.cs" />
<Compile Include="Editors\RelationTypeController.cs" />
<Compile Include="Editors\TinyMceController.cs" />
<Compile Include="FrameworkMarchal.cs" />
<Compile Include="Hosting\AspNetHostingEnvironment.cs" />
<Compile Include="HttpContextAccessorExtensions.cs" />
<Compile Include="HttpContextExtensions.cs" />
<Compile Include="ImageCropperTemplateCoreExtensions.cs" />
<Compile Include="Install\ChangesMonitor.cs" />
@@ -193,6 +196,10 @@
<Compile Include="Scheduling\SchedulerComponent.cs" />
<Compile Include="Scheduling\SchedulerComposer.cs" />
<Compile Include="Security\CurrentUserAccessor.cs" />
<Compile Include="Search\BackgroundIndexRebuilder.cs" />
<Compile Include="Search\ExamineFinalComponent.cs" />
<Compile Include="Search\ExamineFinalComposer.cs" />
<Compile Include="Search\ExamineUserComponent.cs" />
<Compile Include="Security\BackOfficeUserStore.cs" />
<Compile Include="Security\BackOfficeUserValidator.cs" />
<Compile Include="Security\ConfiguredPasswordValidator.cs" />
+2 -2
View File
@@ -57,7 +57,7 @@ namespace Umbraco.Web
//
// all in all, this context may be disposed more than once, but DisposableObject ensures that
// it is ok and it will be actually disposed only once.
httpContextAccessor.HttpContext.DisposeOnPipelineCompleted(this);
httpContextAccessor.GetRequiredHttpContext().DisposeOnPipelineCompleted(this);
ObjectCreated = DateTime.Now;
UmbracoRequestId = Guid.NewGuid();
@@ -207,7 +207,7 @@ namespace Umbraco.Web
{
try
{
return _httpContextAccessor.HttpContext.Request;
return _httpContextAccessor.GetRequiredHttpContext().Request;
}
catch (HttpException)
{
+2 -2
View File
@@ -81,13 +81,13 @@ namespace Umbraco.Web
{
var currentUmbracoContext = _umbracoContextAccessor.UmbracoContext;
if (currentUmbracoContext != null)
return new UmbracoContextReference(false, currentUmbracoContext);
return new UmbracoContextReference(currentUmbracoContext, false, _umbracoContextAccessor);
var umbracoContext = CreateUmbracoContext();
_umbracoContextAccessor.UmbracoContext = umbracoContext;
return new UmbracoContextReference(true, umbracoContext);
return new UmbracoContextReference(umbracoContext, true, _umbracoContextAccessor);
}
// dummy TextWriter that does not write