Merge remote-tracking branch 'origin/v8/8.8' into v8/8.9
# Conflicts: # src/SolutionInfo.cs # src/Umbraco.Web.UI/Umbraco/Views/Default.cshtml
This commit is contained in:
@@ -128,15 +128,16 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
public static void RefreshMemberCache(this DistributedCache dc, params IMember[] members)
|
||||
{
|
||||
dc.Refresh(MemberCacheRefresher.UniqueId, x => x.Id, members);
|
||||
if (members.Length == 0) return;
|
||||
dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username)));
|
||||
}
|
||||
|
||||
public static void RemoveMemberCache(this DistributedCache dc, params IMember[] members)
|
||||
{
|
||||
dc.Remove(MemberCacheRefresher.UniqueId, x => x.Id, members);
|
||||
if (members.Length == 0) return;
|
||||
dc.RefreshByPayload(MemberCacheRefresher.UniqueId, members.Select(x => new MemberCacheRefresher.JsonPayload(x.Id, x.Username)));
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region MemberGroupCache
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
@@ -7,14 +9,30 @@ using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Cache
|
||||
{
|
||||
public sealed class MemberCacheRefresher : TypedCacheRefresherBase<MemberCacheRefresher, IMember>
|
||||
public sealed class MemberCacheRefresher : PayloadCacheRefresherBase<MemberCacheRefresher, MemberCacheRefresher.JsonPayload>
|
||||
{
|
||||
private readonly IdkMap _idkMap;
|
||||
private readonly LegacyMemberCacheRefresher _legacyMemberRefresher;
|
||||
|
||||
public MemberCacheRefresher(AppCaches appCaches, IdkMap idkMap)
|
||||
: base(appCaches)
|
||||
{
|
||||
_idkMap = idkMap;
|
||||
_legacyMemberRefresher = new LegacyMemberCacheRefresher(this, appCaches);
|
||||
}
|
||||
|
||||
public class JsonPayload
|
||||
{
|
||||
[JsonConstructor]
|
||||
public JsonPayload(int id, string username)
|
||||
{
|
||||
Id = id;
|
||||
Username = username;
|
||||
}
|
||||
|
||||
public int Id { get; }
|
||||
public string Username { get; }
|
||||
|
||||
}
|
||||
|
||||
#region Define
|
||||
@@ -31,38 +49,45 @@ namespace Umbraco.Web.Cache
|
||||
|
||||
#region Refresher
|
||||
|
||||
public override void Refresh(JsonPayload[] payloads)
|
||||
{
|
||||
ClearCache(payloads);
|
||||
base.Refresh(payloads);
|
||||
}
|
||||
|
||||
public override void Refresh(int id)
|
||||
{
|
||||
ClearCache(id);
|
||||
ClearCache(new JsonPayload(id, null));
|
||||
base.Refresh(id);
|
||||
}
|
||||
|
||||
public override void Remove(int id)
|
||||
{
|
||||
ClearCache(id);
|
||||
ClearCache(new JsonPayload(id, null));
|
||||
base.Remove(id);
|
||||
}
|
||||
|
||||
public override void Refresh(IMember instance)
|
||||
{
|
||||
ClearCache(instance.Id);
|
||||
base.Refresh(instance);
|
||||
}
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public void Refresh(IMember instance) => _legacyMemberRefresher.Refresh(instance);
|
||||
|
||||
public override void Remove(IMember instance)
|
||||
{
|
||||
ClearCache(instance.Id);
|
||||
base.Remove(instance);
|
||||
}
|
||||
[Obsolete("This is no longer used and will be removed from the codebase in the future")]
|
||||
public void Remove(IMember instance) => _legacyMemberRefresher.Remove(instance);
|
||||
|
||||
private void ClearCache(int id)
|
||||
private void ClearCache(params JsonPayload[] payloads)
|
||||
{
|
||||
_idkMap.ClearCache(id);
|
||||
AppCaches.ClearPartialViewCache();
|
||||
|
||||
var memberCache = AppCaches.IsolatedCaches.Get<IMember>();
|
||||
if (memberCache)
|
||||
memberCache.Result.Clear(RepositoryCacheKeys.GetKey<IMember>(id));
|
||||
|
||||
foreach (var p in payloads)
|
||||
{
|
||||
_idkMap.ClearCache(p.Id);
|
||||
if (memberCache)
|
||||
{
|
||||
memberCache.Result.Clear(RepositoryCacheKeys.GetKey<IMember>(p.Id));
|
||||
memberCache.Result.Clear(RepositoryCacheKeys.GetKey<IMember>(p.Username));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -75,5 +100,38 @@ namespace Umbraco.Web.Cache
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Backwards Compat
|
||||
|
||||
// TODO: this is here purely for backwards compat but should be removed in netcore
|
||||
private class LegacyMemberCacheRefresher : TypedCacheRefresherBase<MemberCacheRefresher, IMember>
|
||||
{
|
||||
private readonly MemberCacheRefresher _parent;
|
||||
|
||||
public LegacyMemberCacheRefresher(MemberCacheRefresher parent, AppCaches appCaches) : base(appCaches)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
public override Guid RefresherUniqueId => _parent.RefresherUniqueId;
|
||||
|
||||
public override string Name => _parent.Name;
|
||||
|
||||
protected override MemberCacheRefresher This => _parent;
|
||||
|
||||
public override void Refresh(IMember instance)
|
||||
{
|
||||
_parent.ClearCache(new JsonPayload(instance.Id, instance.Username));
|
||||
base.Refresh(instance.Id);
|
||||
}
|
||||
|
||||
public override void Remove(IMember instance)
|
||||
{
|
||||
_parent.ClearCache(new JsonPayload(instance.Id, instance.Username));
|
||||
base.Remove(instance);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,19 @@ namespace Umbraco.Web.Compose
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
//BackOfficeUserManager.AccountLocked -= ;
|
||||
//BackOfficeUserManager.AccountUnlocked -= ;
|
||||
BackOfficeUserManager.ForgotPasswordRequested -= OnForgotPasswordRequest;
|
||||
BackOfficeUserManager.ForgotPasswordChangedSuccess -= OnForgotPasswordChange;
|
||||
BackOfficeUserManager.LoginFailed -= OnLoginFailed;
|
||||
//BackOfficeUserManager.LoginRequiresVerification -= ;
|
||||
BackOfficeUserManager.LoginSuccess -= OnLoginSuccess;
|
||||
BackOfficeUserManager.LogoutSuccess -= OnLogoutSuccess;
|
||||
BackOfficeUserManager.PasswordChanged -= OnPasswordChanged;
|
||||
BackOfficeUserManager.PasswordReset -= OnPasswordReset;
|
||||
//BackOfficeUserManager.ResetAccessFailedCount -= ;
|
||||
}
|
||||
|
||||
private IUser GetPerformingUser(int userId)
|
||||
{
|
||||
|
||||
@@ -32,42 +32,78 @@ namespace Umbraco.Web.Compose
|
||||
public void Initialize()
|
||||
{
|
||||
//Send notifications for the send to publish action
|
||||
ContentService.SentToPublish += (sender, args) => _notifier.Notify(_actions.GetAction<ActionToPublish>(), args.Entity);
|
||||
|
||||
ContentService.SentToPublish += ContentService_SentToPublish;
|
||||
//Send notifications for the published action
|
||||
ContentService.Published += (sender, args) => _notifier.Notify(_actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());
|
||||
|
||||
ContentService.Published += ContentService_Published;
|
||||
//Send notifications for the saved action
|
||||
ContentService.Sorted += (sender, args) => ContentServiceSorted(_notifier, sender, args, _actions);
|
||||
|
||||
ContentService.Sorted += ContentService_Sorted;
|
||||
//Send notifications for the update and created actions
|
||||
ContentService.Saved += (sender, args) => ContentServiceSaved(_notifier, sender, args, _actions);
|
||||
|
||||
ContentService.Saved += ContentService_Saved;
|
||||
//Send notifications for the unpublish action
|
||||
ContentService.Unpublished += (sender, args) => _notifier.Notify(_actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());
|
||||
|
||||
ContentService.Unpublished += ContentService_Unpublished;
|
||||
//Send notifications for the move/move to recycle bin and restore actions
|
||||
ContentService.Moved += (sender, args) => ContentServiceMoved(_notifier, sender, args, _actions);
|
||||
|
||||
ContentService.Moved += ContentService_Moved;
|
||||
//Send notifications for the delete action when content is moved to the recycle bin
|
||||
ContentService.Trashed += (sender, args) => _notifier.Notify(_actions.GetAction<ActionDelete>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());
|
||||
|
||||
ContentService.Trashed += ContentService_Trashed;
|
||||
//Send notifications for the copy action
|
||||
ContentService.Copied += (sender, args) => _notifier.Notify(_actions.GetAction<ActionCopy>(), args.Original);
|
||||
|
||||
ContentService.Copied += ContentService_Copied;
|
||||
//Send notifications for the rollback action
|
||||
ContentService.RolledBack += (sender, args) => _notifier.Notify(_actions.GetAction<ActionRollback>(), args.Entity);
|
||||
|
||||
ContentService.RolledBack += ContentService_RolledBack;
|
||||
//Send notifications for the public access changed action
|
||||
PublicAccessService.Saved += (sender, args) => PublicAccessServiceSaved(_notifier, sender, args, _contentService, _actions);
|
||||
|
||||
UserService.UserGroupPermissionsAssigned += (sender, args) => UserServiceUserGroupPermissionsAssigned(_notifier, sender, args, _contentService, _actions);
|
||||
PublicAccessService.Saved += PublicAccessService_Saved;
|
||||
|
||||
UserService.UserGroupPermissionsAssigned += UserService_UserGroupPermissionsAssigned;
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
ContentService.SentToPublish -= ContentService_SentToPublish;
|
||||
ContentService.Published -= ContentService_Published;
|
||||
ContentService.Sorted -= ContentService_Sorted;
|
||||
ContentService.Saved -= ContentService_Saved;
|
||||
ContentService.Unpublished -= ContentService_Unpublished;
|
||||
ContentService.Moved -= ContentService_Moved;
|
||||
ContentService.Trashed -= ContentService_Trashed;
|
||||
ContentService.Copied -= ContentService_Copied;
|
||||
ContentService.RolledBack -= ContentService_RolledBack;
|
||||
PublicAccessService.Saved -= PublicAccessService_Saved;
|
||||
UserService.UserGroupPermissionsAssigned -= UserService_UserGroupPermissionsAssigned;
|
||||
}
|
||||
|
||||
private void ContentServiceSorted(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs<IContent> args, ActionCollection actions)
|
||||
private void UserService_UserGroupPermissionsAssigned(IUserService sender, Core.Events.SaveEventArgs<EntityPermission> args)
|
||||
=> UserServiceUserGroupPermissionsAssigned(args, _contentService);
|
||||
|
||||
private void PublicAccessService_Saved(IPublicAccessService sender, Core.Events.SaveEventArgs<PublicAccessEntry> args)
|
||||
=> PublicAccessServiceSaved(args, _contentService);
|
||||
|
||||
private void ContentService_RolledBack(IContentService sender, Core.Events.RollbackEventArgs<IContent> args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionRollback>(), args.Entity);
|
||||
|
||||
private void ContentService_Copied(IContentService sender, Core.Events.CopyEventArgs<IContent> args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionCopy>(), args.Original);
|
||||
|
||||
private void ContentService_Trashed(IContentService sender, Core.Events.MoveEventArgs<IContent> args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionDelete>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());
|
||||
|
||||
private void ContentService_Moved(IContentService sender, Core.Events.MoveEventArgs<IContent> args)
|
||||
=> ContentServiceMoved(args);
|
||||
|
||||
private void ContentService_Unpublished(IContentService sender, Core.Events.PublishEventArgs<IContent> args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionUnpublish>(), args.PublishedEntities.ToArray());
|
||||
|
||||
private void ContentService_Saved(IContentService sender, Core.Events.ContentSavedEventArgs args)
|
||||
=> ContentServiceSaved(args);
|
||||
|
||||
private void ContentService_Sorted(IContentService sender, Core.Events.SaveEventArgs<IContent> args)
|
||||
=> ContentServiceSorted(sender, args);
|
||||
|
||||
private void ContentService_Published(IContentService sender, Core.Events.ContentPublishedEventArgs args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionPublish>(), args.PublishedEntities.ToArray());
|
||||
|
||||
private void ContentService_SentToPublish(IContentService sender, Core.Events.SendToPublishEventArgs<IContent> args)
|
||||
=> _notifier.Notify(_actions.GetAction<ActionToPublish>(), args.Entity);
|
||||
|
||||
private void ContentServiceSorted(IContentService sender, Core.Events.SaveEventArgs<IContent> args)
|
||||
{
|
||||
var parentId = args.SavedEntities.Select(x => x.ParentId).Distinct().ToList();
|
||||
if (parentId.Count != 1) return; // this shouldn't happen, for sorting all entities will have the same parent id
|
||||
@@ -79,10 +115,10 @@ namespace Umbraco.Web.Compose
|
||||
var parent = sender.GetById(parentId[0]);
|
||||
if (parent == null) return; // this shouldn't happen
|
||||
|
||||
notifier.Notify(actions.GetAction<ActionSort>(), new[] { parent });
|
||||
_notifier.Notify(_actions.GetAction<ActionSort>(), new[] { parent });
|
||||
}
|
||||
|
||||
private void ContentServiceSaved(Notifier notifier, IContentService sender, Core.Events.SaveEventArgs<IContent> args, ActionCollection actions)
|
||||
private void ContentServiceSaved(Core.Events.SaveEventArgs<IContent> args)
|
||||
{
|
||||
var newEntities = new List<IContent>();
|
||||
var updatedEntities = new List<IContent>();
|
||||
@@ -102,21 +138,21 @@ namespace Umbraco.Web.Compose
|
||||
updatedEntities.Add(entity);
|
||||
}
|
||||
}
|
||||
notifier.Notify(actions.GetAction<ActionNew>(), newEntities.ToArray());
|
||||
notifier.Notify(actions.GetAction<ActionUpdate>(), updatedEntities.ToArray());
|
||||
_notifier.Notify(_actions.GetAction<ActionNew>(), newEntities.ToArray());
|
||||
_notifier.Notify(_actions.GetAction<ActionUpdate>(), updatedEntities.ToArray());
|
||||
}
|
||||
|
||||
private void UserServiceUserGroupPermissionsAssigned(Notifier notifier, IUserService sender, Core.Events.SaveEventArgs<EntityPermission> args, IContentService contentService, ActionCollection actions)
|
||||
private void UserServiceUserGroupPermissionsAssigned(Core.Events.SaveEventArgs<EntityPermission> args, IContentService contentService)
|
||||
{
|
||||
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.EntityId)).ToArray();
|
||||
if(entities.Any() == false)
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
notifier.Notify(actions.GetAction<ActionRights>(), entities);
|
||||
_notifier.Notify(_actions.GetAction<ActionRights>(), entities);
|
||||
}
|
||||
|
||||
private void ContentServiceMoved(Notifier notifier, IContentService sender, Core.Events.MoveEventArgs<IContent> args, ActionCollection actions)
|
||||
|
||||
private void ContentServiceMoved(Core.Events.MoveEventArgs<IContent> args)
|
||||
{
|
||||
// notify about the move for all moved items
|
||||
_notifier.Notify(_actions.GetAction<ActionMove>(), args.MoveInfoCollection.Select(m => m.Entity).ToArray());
|
||||
@@ -126,22 +162,22 @@ namespace Umbraco.Web.Compose
|
||||
.Where(m => m.OriginalPath.Contains(Constants.System.RecycleBinContentString))
|
||||
.Select(m => m.Entity)
|
||||
.ToArray();
|
||||
if(restoredEntities.Any())
|
||||
if (restoredEntities.Any())
|
||||
{
|
||||
_notifier.Notify(_actions.GetAction<ActionRestore>(), restoredEntities);
|
||||
}
|
||||
}
|
||||
|
||||
private void PublicAccessServiceSaved(Notifier notifier, IPublicAccessService sender, Core.Events.SaveEventArgs<PublicAccessEntry> args, IContentService contentService, ActionCollection actions)
|
||||
private void PublicAccessServiceSaved(Core.Events.SaveEventArgs<PublicAccessEntry> args, IContentService contentService)
|
||||
{
|
||||
var entities = contentService.GetByIds(args.SavedEntities.Select(e => e.ProtectedNodeId)).ToArray();
|
||||
if(entities.Any() == false)
|
||||
if (entities.Any() == false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
notifier.Notify(actions.GetAction<ActionProtect>(), entities);
|
||||
_notifier.Notify(_actions.GetAction<ActionProtect>(), entities);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This class is used to send the notifications
|
||||
/// </summary>
|
||||
|
||||
@@ -14,7 +14,9 @@ namespace Umbraco.Web.Compose
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
MemberGroupService.Saved -= MemberGroupService_Saved;
|
||||
}
|
||||
|
||||
static void MemberGroupService_Saved(IMemberGroupService sender, Core.Events.SaveEventArgs<Core.Models.IMemberGroup> e)
|
||||
{
|
||||
|
||||
@@ -146,6 +146,9 @@ namespace Umbraco.Web.Composing
|
||||
public static ISectionService SectionService
|
||||
=> Factory.GetInstance<ISectionService>();
|
||||
|
||||
public static IIconService IconService
|
||||
=> Factory.GetInstance<IIconService>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Web Constants
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@@ -14,7 +13,6 @@ using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Manifest;
|
||||
using Umbraco.Core.Models.Identity;
|
||||
@@ -25,6 +23,7 @@ using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Features;
|
||||
using Umbraco.Web.JavaScript;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.Services;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using JArray = Newtonsoft.Json.Linq.JArray;
|
||||
|
||||
@@ -41,15 +40,52 @@ namespace Umbraco.Web.Editors
|
||||
private readonly ManifestParser _manifestParser;
|
||||
private readonly UmbracoFeatures _features;
|
||||
private readonly IRuntimeState _runtimeState;
|
||||
private readonly IIconService _iconService;
|
||||
private BackOfficeUserManager<BackOfficeIdentityUser> _userManager;
|
||||
private BackOfficeSignInManager _signInManager;
|
||||
|
||||
public BackOfficeController(ManifestParser manifestParser, UmbracoFeatures features, IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ServiceContext services, AppCaches appCaches, IProfilingLogger profilingLogger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper)
|
||||
[Obsolete("Use the constructor that injects IIconService.")]
|
||||
public BackOfficeController(
|
||||
ManifestParser manifestParser,
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ServiceContext services,
|
||||
AppCaches appCaches,
|
||||
IProfilingLogger profilingLogger,
|
||||
IRuntimeState runtimeState,
|
||||
UmbracoHelper umbracoHelper)
|
||||
: this(manifestParser,
|
||||
features,
|
||||
globalSettings,
|
||||
umbracoContextAccessor,
|
||||
services,
|
||||
appCaches,
|
||||
profilingLogger,
|
||||
runtimeState,
|
||||
umbracoHelper,
|
||||
Current.IconService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public BackOfficeController(
|
||||
ManifestParser manifestParser,
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ServiceContext services,
|
||||
AppCaches appCaches,
|
||||
IProfilingLogger profilingLogger,
|
||||
IRuntimeState runtimeState,
|
||||
UmbracoHelper umbracoHelper,
|
||||
IIconService iconService)
|
||||
: base(globalSettings, umbracoContextAccessor, services, appCaches, profilingLogger, umbracoHelper)
|
||||
{
|
||||
_manifestParser = manifestParser;
|
||||
_features = features;
|
||||
_runtimeState = runtimeState;
|
||||
_iconService = iconService;
|
||||
}
|
||||
|
||||
protected BackOfficeSignInManager SignInManager => _signInManager ?? (_signInManager = OwinContext.GetBackOfficeSignInManager());
|
||||
@@ -64,9 +100,10 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
public async Task<ActionResult> Default()
|
||||
{
|
||||
var backofficeModel = new BackOfficeModel(_features, GlobalSettings, _iconService);
|
||||
return await RenderDefaultOrProcessExternalLoginAsync(
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)),
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", new BackOfficeModel(_features, GlobalSettings)));
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", backofficeModel),
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Default.cshtml", backofficeModel));
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
@@ -149,7 +186,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
return await RenderDefaultOrProcessExternalLoginAsync(
|
||||
//The default view to render when there is no external login info or errors
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings)),
|
||||
() => View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/AuthorizeUpgrade.cshtml", new BackOfficeModel(_features, GlobalSettings, _iconService)),
|
||||
//The ActionResult to perform if external login is successful
|
||||
() => Redirect("/"));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using Umbraco.Core.Configuration;
|
||||
using System;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Features;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
@@ -6,13 +9,24 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public class BackOfficeModel
|
||||
{
|
||||
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings)
|
||||
|
||||
|
||||
[Obsolete("Use the overload that injects IIconService.")]
|
||||
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings) : this(features, globalSettings, Current.IconService)
|
||||
{
|
||||
|
||||
}
|
||||
public BackOfficeModel(UmbracoFeatures features, IGlobalSettings globalSettings, IIconService iconService)
|
||||
{
|
||||
Features = features;
|
||||
GlobalSettings = globalSettings;
|
||||
IconCheckData = iconService.GetIcon("icon-check")?.SvgString;
|
||||
IconDeleteData = iconService.GetIcon("icon-delete")?.SvgString;
|
||||
}
|
||||
|
||||
|
||||
public UmbracoFeatures Features { get; }
|
||||
public IGlobalSettings GlobalSettings { get; }
|
||||
public string IconCheckData { get; }
|
||||
public string IconDeleteData { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Features;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
@@ -10,7 +13,21 @@ namespace Umbraco.Web.Editors
|
||||
private readonly UmbracoFeatures _features;
|
||||
public IEnumerable<ILanguage> Languages { get; }
|
||||
|
||||
public BackOfficePreviewModel(UmbracoFeatures features, IGlobalSettings globalSettings, IEnumerable<ILanguage> languages) : base(features, globalSettings)
|
||||
[Obsolete("Use the overload that injects IIconService.")]
|
||||
public BackOfficePreviewModel(
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IEnumerable<ILanguage> languages)
|
||||
: this(features, globalSettings, languages, Current.IconService)
|
||||
{
|
||||
}
|
||||
|
||||
public BackOfficePreviewModel(
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IEnumerable<ILanguage> languages,
|
||||
IIconService iconService)
|
||||
: base(features, globalSettings, iconService)
|
||||
{
|
||||
_features = features;
|
||||
Languages = languages;
|
||||
|
||||
@@ -1,21 +1,20 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Models;
|
||||
using System.IO;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Ganss.XSS;
|
||||
using Umbraco.Core.Cache;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
[PluginController("UmbracoApi")]
|
||||
public class IconController : UmbracoAuthorizedApiController
|
||||
{
|
||||
private readonly IIconService _iconService;
|
||||
|
||||
public IconController(IIconService iconService)
|
||||
{
|
||||
_iconService = iconService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IconModel containing the icon name and SvgString according to an icon name found at the global icons path
|
||||
@@ -24,76 +23,16 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
public IconModel GetIcon(string iconName)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(iconName)
|
||||
? null
|
||||
: CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{GlobalSettings.IconsPath}/{iconName}.svg"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IconModel using values from a FileInfo model
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <returns></returns>
|
||||
public IconModel GetIcon(FileInfo fileInfo)
|
||||
{
|
||||
return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name)
|
||||
? null
|
||||
: CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName);
|
||||
return _iconService.GetIcon(iconName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all svg icons found at at the global icons path.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<IconModel> GetAllIcons()
|
||||
public IList<IconModel> GetAllIcons()
|
||||
{
|
||||
var icons = new List<IconModel>();
|
||||
var directory = new DirectoryInfo(IOHelper.MapPath($"{GlobalSettings.IconsPath}/"));
|
||||
var iconNames = directory.GetFiles("*.svg");
|
||||
|
||||
iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo =>
|
||||
{
|
||||
var icon = GetIcon(iconInfo);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
icons.Add(icon);
|
||||
}
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IconModel containing the icon name and SvgString
|
||||
/// </summary>
|
||||
/// <param name="iconName"></param>
|
||||
/// <param name="iconPath"></param>
|
||||
/// <returns></returns>
|
||||
private IconModel CreateIconModel(string iconName, string iconPath)
|
||||
{
|
||||
var sanitizer = new HtmlSanitizer();
|
||||
sanitizer.AllowedAttributes.UnionWith(Core.Constants.SvgSanitizer.Attributes);
|
||||
sanitizer.AllowedCssProperties.UnionWith(Core.Constants.SvgSanitizer.Attributes);
|
||||
sanitizer.AllowedTags.UnionWith(Core.Constants.SvgSanitizer.Tags);
|
||||
|
||||
try
|
||||
{
|
||||
var svgContent = File.ReadAllText(iconPath);
|
||||
var sanitizedString = sanitizer.Sanitize(svgContent);
|
||||
|
||||
var svg = new IconModel
|
||||
{
|
||||
Name = iconName,
|
||||
SvgString = sanitizedString
|
||||
};
|
||||
|
||||
return svg;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return _iconService.GetAllIcons();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ using Umbraco.Web.JavaScript;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Services;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
@@ -24,19 +25,39 @@ namespace Umbraco.Web.Editors
|
||||
private readonly IPublishedSnapshotService _publishedSnapshotService;
|
||||
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly IIconService _iconService;
|
||||
|
||||
[Obsolete("Use the constructor that injects IIconService.")]
|
||||
public PreviewController(
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IPublishedSnapshotService publishedSnapshotService,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ILocalizationService localizationService)
|
||||
:this(features,
|
||||
globalSettings,
|
||||
publishedSnapshotService,
|
||||
umbracoContextAccessor,
|
||||
localizationService,
|
||||
Current.IconService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public PreviewController(
|
||||
UmbracoFeatures features,
|
||||
IGlobalSettings globalSettings,
|
||||
IPublishedSnapshotService publishedSnapshotService,
|
||||
IUmbracoContextAccessor umbracoContextAccessor,
|
||||
ILocalizationService localizationService,
|
||||
IIconService iconService)
|
||||
{
|
||||
_features = features;
|
||||
_globalSettings = globalSettings;
|
||||
_publishedSnapshotService = publishedSnapshotService;
|
||||
_umbracoContextAccessor = umbracoContextAccessor;
|
||||
_localizationService = localizationService;
|
||||
_iconService = iconService;
|
||||
}
|
||||
|
||||
[UmbracoAuthorize(redirectToUmbracoLogin: true)]
|
||||
@@ -45,7 +66,7 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
var availableLanguages = _localizationService.GetAllLanguages();
|
||||
|
||||
var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages);
|
||||
var model = new BackOfficePreviewModel(_features, _globalSettings, availableLanguages, _iconService);
|
||||
|
||||
if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Web;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -9,6 +10,7 @@ namespace Umbraco.Web.Logging
|
||||
{
|
||||
private readonly WebProfiler _profiler;
|
||||
private readonly bool _profile;
|
||||
private readonly List<Action> _terminate = new List<Action>();
|
||||
|
||||
public WebProfilerComponent(IProfiler profiler, ILogger logger)
|
||||
{
|
||||
@@ -35,15 +37,23 @@ namespace Umbraco.Web.Logging
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
UmbracoApplicationBase.ApplicationInit -= InitializeApplication;
|
||||
foreach (var t in _terminate) t();
|
||||
}
|
||||
|
||||
private void InitializeApplication(object sender, EventArgs args)
|
||||
{
|
||||
if (!(sender is HttpApplication app)) return;
|
||||
|
||||
// for *each* application (this will run more than once)
|
||||
app.BeginRequest += (s, a) => _profiler.UmbracoApplicationBeginRequest(s, a);
|
||||
app.EndRequest += (s, a) => _profiler.UmbracoApplicationEndRequest(s, a);
|
||||
void beginRequest(object s, EventArgs a) => _profiler.UmbracoApplicationBeginRequest(s, a);
|
||||
app.BeginRequest += beginRequest;
|
||||
_terminate.Add(() => app.BeginRequest -= beginRequest);
|
||||
|
||||
void endRequest(object s, EventArgs a) => _profiler.UmbracoApplicationEndRequest(s, a);
|
||||
app.EndRequest += endRequest;
|
||||
_terminate.Add(() => app.EndRequest -= endRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
public class IconModel
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string SvgString { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
using System.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Events;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
@@ -9,6 +13,7 @@ namespace Umbraco.Web.PropertyEditors
|
||||
internal sealed class PropertyEditorsComponent : IComponent
|
||||
{
|
||||
private readonly PropertyEditorCollection _propertyEditors;
|
||||
private readonly List<Action> _terminate = new List<Action>();
|
||||
|
||||
public PropertyEditorsComponent(PropertyEditorCollection propertyEditors)
|
||||
{
|
||||
@@ -27,32 +32,48 @@ namespace Umbraco.Web.PropertyEditors
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
|
||||
private static void Initialize(FileUploadPropertyEditor fileUpload)
|
||||
{
|
||||
MediaService.Saving += fileUpload.MediaServiceSaving;
|
||||
ContentService.Copied += fileUpload.ContentServiceCopied;
|
||||
|
||||
MediaService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
ContentService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
foreach (var t in _terminate) t();
|
||||
}
|
||||
|
||||
private static void Initialize(ImageCropperPropertyEditor imageCropper)
|
||||
private void Initialize(FileUploadPropertyEditor fileUpload)
|
||||
{
|
||||
MediaService.Saving += fileUpload.MediaServiceSaving;
|
||||
_terminate.Add(() => MediaService.Saving -= fileUpload.MediaServiceSaving);
|
||||
ContentService.Copied += fileUpload.ContentServiceCopied;
|
||||
_terminate.Add(() => ContentService.Copied -= fileUpload.ContentServiceCopied);
|
||||
|
||||
void mediaServiceDeleted(IMediaService sender, DeleteEventArgs<IMedia> args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MediaService.Deleted += mediaServiceDeleted;
|
||||
_terminate.Add(() => MediaService.Deleted -= mediaServiceDeleted);
|
||||
|
||||
void contentServiceDeleted(IContentService sender, DeleteEventArgs<IContent> args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
ContentService.Deleted += contentServiceDeleted;
|
||||
_terminate.Add(() => ContentService.Deleted -= contentServiceDeleted);
|
||||
|
||||
void memberServiceDeleted(IMemberService sender, DeleteEventArgs<IMember> args) => args.MediaFilesToDelete.AddRange(fileUpload.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += memberServiceDeleted;
|
||||
_terminate.Add(() => MemberService.Deleted -= memberServiceDeleted);
|
||||
}
|
||||
|
||||
private void Initialize(ImageCropperPropertyEditor imageCropper)
|
||||
{
|
||||
MediaService.Saving += imageCropper.MediaServiceSaving;
|
||||
_terminate.Add(() => MediaService.Saving -= imageCropper.MediaServiceSaving);
|
||||
ContentService.Copied += imageCropper.ContentServiceCopied;
|
||||
_terminate.Add(() => ContentService.Copied -= imageCropper.ContentServiceCopied);
|
||||
|
||||
MediaService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
ContentService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += (sender, args)
|
||||
=> args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
void mediaServiceDeleted(IMediaService sender, DeleteEventArgs<IMedia> args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MediaService.Deleted += mediaServiceDeleted;
|
||||
_terminate.Add(() => MediaService.Deleted -= mediaServiceDeleted);
|
||||
|
||||
void contentServiceDeleted(IContentService sender, DeleteEventArgs<IContent> args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
ContentService.Deleted += contentServiceDeleted;
|
||||
_terminate.Add(() => ContentService.Deleted -= contentServiceDeleted);
|
||||
|
||||
void memberServiceDeleted(IMemberService sender, DeleteEventArgs<IMember> args) => args.MediaFilesToDelete.AddRange(imageCropper.ServiceDeleted(args.DeletedEntities.Cast<ContentBase>()));
|
||||
MemberService.Deleted += memberServiceDeleted;
|
||||
_terminate.Add(() => MemberService.Deleted -= memberServiceDeleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,12 @@ namespace Umbraco.Web.Routing
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
ContentService.Publishing -= ContentService_Publishing;
|
||||
ContentService.Published -= ContentService_Published;
|
||||
ContentService.Moving -= ContentService_Moving;
|
||||
ContentService.Moved -= ContentService_Moved;
|
||||
}
|
||||
|
||||
private void ContentService_Publishing(IContentService sender, PublishEventArgs<IContent> args)
|
||||
{
|
||||
|
||||
@@ -137,8 +137,8 @@ namespace Umbraco.Web.Runtime
|
||||
composition.RegisterUnique<IEventMessagesAccessor, HybridEventMessagesAccessor>();
|
||||
composition.RegisterUnique<ITreeService, TreeService>();
|
||||
composition.RegisterUnique<ISectionService, SectionService>();
|
||||
|
||||
composition.RegisterUnique<IDashboardService, DashboardService>();
|
||||
composition.RegisterUnique<IIconService, IconService>();
|
||||
|
||||
composition.RegisterUnique<IExamineManager>(factory => ExamineManager.Instance);
|
||||
|
||||
|
||||
32
src/Umbraco.Web/Scheduling/SimpleTask.cs
Normal file
32
src/Umbraco.Web/Scheduling/SimpleTask.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Scheduling
|
||||
{
|
||||
/// <summary>
|
||||
/// A simple task that executes a delegate synchronously
|
||||
/// </summary>
|
||||
internal class SimpleTask : IBackgroundTask
|
||||
{
|
||||
private readonly Action _action;
|
||||
|
||||
public SimpleTask(Action action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public bool IsAsync => false;
|
||||
|
||||
public void Run() => _action();
|
||||
|
||||
public Task RunAsync(CancellationToken token)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,13 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Examine.LuceneEngine.Directories;
|
||||
using Umbraco.Core.Composing;
|
||||
using System.ComponentModel;
|
||||
using System.Threading;
|
||||
using Umbraco.Web.Scheduling;
|
||||
|
||||
namespace Umbraco.Web.Search
|
||||
{
|
||||
|
||||
|
||||
public sealed class ExamineComponent : Umbraco.Core.Composing.IComponent
|
||||
{
|
||||
private readonly IExamineManager _examineManager;
|
||||
@@ -34,7 +38,8 @@ namespace Umbraco.Web.Search
|
||||
private readonly IMainDom _mainDom;
|
||||
private readonly IProfilingLogger _logger;
|
||||
private readonly IUmbracoIndexesCreator _indexCreator;
|
||||
|
||||
private readonly BackgroundTaskRunner<IBackgroundTask> _indexItemTaskRunner;
|
||||
|
||||
|
||||
// the default enlist priority is 100
|
||||
// enlist with a lower priority to ensure that anything "default" runs after us
|
||||
@@ -62,6 +67,7 @@ namespace Umbraco.Web.Search
|
||||
_mainDom = mainDom;
|
||||
_logger = profilingLogger;
|
||||
_indexCreator = indexCreator;
|
||||
_indexItemTaskRunner = new BackgroundTaskRunner<IBackgroundTask>(_logger);
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
@@ -117,7 +123,13 @@ namespace Umbraco.Web.Search
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{ }
|
||||
{
|
||||
ContentCacheRefresher.CacheUpdated -= ContentCacheRefresherUpdated;
|
||||
ContentTypeCacheRefresher.CacheUpdated -= ContentTypeCacheRefresherUpdated;
|
||||
MediaCacheRefresher.CacheUpdated -= MediaCacheRefresherUpdated;
|
||||
MemberCacheRefresher.CacheUpdated -= MemberCacheRefresherUpdated;
|
||||
LanguageCacheRefresher.CacheUpdated -= LanguageCacheRefresherUpdated;
|
||||
}
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[Obsolete("This method should not be used and will be removed in future versions, rebuilding indexes can be done with the IndexRebuilder or the BackgroundIndexRebuilder")]
|
||||
@@ -574,12 +586,18 @@ namespace Umbraco.Web.Search
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An action that will execute at the end of the Scope being completed
|
||||
/// </summary>
|
||||
private abstract class DeferedAction
|
||||
{
|
||||
public virtual void Execute()
|
||||
{ }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-indexes an <see cref="IContent"/> item on a background thread
|
||||
/// </summary>
|
||||
private class DeferedReIndexForContent : DeferedAction
|
||||
{
|
||||
private readonly ExamineComponent _examineComponent;
|
||||
@@ -600,21 +618,32 @@ namespace Umbraco.Web.Search
|
||||
|
||||
public static void Execute(ExamineComponent examineComponent, IContent content, bool isPublished)
|
||||
{
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => isPublished || !x.PublishedValuesOnly)
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
// perform the ValueSet lookup on a background thread
|
||||
examineComponent._indexItemTaskRunner.Add(new SimpleTask(() =>
|
||||
{
|
||||
//for content we have a different builder for published vs unpublished
|
||||
var builder = index.PublishedValuesOnly
|
||||
? examineComponent._publishedContentValueSetBuilder
|
||||
: (IValueSetBuilder<IContent>)examineComponent._contentValueSetBuilder;
|
||||
// for content we have a different builder for published vs unpublished
|
||||
// we don't want to build more value sets than is needed so we'll lazily build 2 one for published one for non-published
|
||||
var builders = new Dictionary<bool, Lazy<List<ValueSet>>>
|
||||
{
|
||||
[true] = new Lazy<List<ValueSet>>(() => examineComponent._publishedContentValueSetBuilder.GetValueSets(content).ToList()),
|
||||
[false] = new Lazy<List<ValueSet>>(() => examineComponent._contentValueSetBuilder.GetValueSets(content).ToList())
|
||||
};
|
||||
|
||||
index.IndexItems(builder.GetValueSets(content));
|
||||
}
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => isPublished || !x.PublishedValuesOnly)
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
{
|
||||
var valueSet = builders[index.PublishedValuesOnly].Value;
|
||||
index.IndexItems(valueSet);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-indexes an <see cref="IMedia"/> item on a background thread
|
||||
/// </summary>
|
||||
private class DeferedReIndexForMedia : DeferedAction
|
||||
{
|
||||
private readonly ExamineComponent _examineComponent;
|
||||
@@ -635,18 +664,25 @@ namespace Umbraco.Web.Search
|
||||
|
||||
public static void Execute(ExamineComponent examineComponent, IMedia media, bool isPublished)
|
||||
{
|
||||
var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList();
|
||||
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => isPublished || !x.PublishedValuesOnly)
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
// perform the ValueSet lookup on a background thread
|
||||
examineComponent._indexItemTaskRunner.Add(new SimpleTask(() =>
|
||||
{
|
||||
index.IndexItems(valueSet);
|
||||
}
|
||||
var valueSet = examineComponent._mediaValueSetBuilder.GetValueSets(media).ToList();
|
||||
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => isPublished || !x.PublishedValuesOnly)
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
{
|
||||
index.IndexItems(valueSet);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Re-indexes an <see cref="IMember"/> item on a background thread
|
||||
/// </summary>
|
||||
private class DeferedReIndexForMember : DeferedAction
|
||||
{
|
||||
private readonly ExamineComponent _examineComponent;
|
||||
@@ -665,13 +701,17 @@ namespace Umbraco.Web.Search
|
||||
|
||||
public static void Execute(ExamineComponent examineComponent, IMember member)
|
||||
{
|
||||
var valueSet = examineComponent._memberValueSetBuilder.GetValueSets(member).ToList();
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
// perform the ValueSet lookup on a background thread
|
||||
examineComponent._indexItemTaskRunner.Add(new SimpleTask(() =>
|
||||
{
|
||||
index.IndexItems(valueSet);
|
||||
}
|
||||
var valueSet = examineComponent._memberValueSetBuilder.GetValueSets(member).ToList();
|
||||
foreach (var index in examineComponent._examineManager.Indexes.OfType<IUmbracoIndex>()
|
||||
//filter the indexers
|
||||
.Where(x => x.EnableDefaultEventHandler))
|
||||
{
|
||||
index.IndexItems(valueSet);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -309,8 +309,9 @@ namespace Umbraco.Web.Security
|
||||
{
|
||||
return false;
|
||||
}
|
||||
//Set member online
|
||||
var member = provider.GetUser(username, true);
|
||||
// Get the member, do not set to online - this is done implicitly as part of ValidateUser which is consistent with
|
||||
// how the .NET framework SqlMembershipProvider works. Passing in true will just cause more unnecessary SQL queries/locks.
|
||||
var member = provider.GetUser(username, false);
|
||||
if (member == null)
|
||||
{
|
||||
//this should not happen
|
||||
@@ -826,33 +827,17 @@ namespace Umbraco.Web.Security
|
||||
/// <returns></returns>
|
||||
private IMember GetCurrentPersistedMember()
|
||||
{
|
||||
return _appCaches.RequestCache.GetCacheItem<IMember>(
|
||||
GetCacheKey("GetCurrentPersistedMember"), () =>
|
||||
{
|
||||
var provider = _membershipProvider;
|
||||
var provider = _membershipProvider;
|
||||
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
throw new NotSupportedException("An IMember model can only be retrieved when using the built-in Umbraco membership providers");
|
||||
}
|
||||
var username = provider.GetCurrentUserName();
|
||||
var member = _memberService.GetByUsername(username);
|
||||
return member;
|
||||
});
|
||||
}
|
||||
|
||||
private static string GetCacheKey(string key, params object[] additional)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(typeof(MembershipHelper).Name);
|
||||
sb.Append("-");
|
||||
sb.Append(key);
|
||||
foreach (var s in additional)
|
||||
if (provider.IsUmbracoMembershipProvider() == false)
|
||||
{
|
||||
sb.Append("-");
|
||||
sb.Append(s);
|
||||
throw new NotSupportedException("An IMember model can only be retrieved when using the built-in Umbraco membership providers");
|
||||
}
|
||||
return sb.ToString();
|
||||
var username = provider.GetCurrentUserName();
|
||||
|
||||
// The result of this is cached by the MemberRepository
|
||||
var member = _memberService.GetByUsername(username);
|
||||
return member;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -348,15 +348,16 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
if (userIsOnline)
|
||||
{
|
||||
member.LastLoginDate = DateTime.Now;
|
||||
member.UpdateDate = DateTime.Now;
|
||||
//don't raise events for this! It just sets the member dates, if we do raise events this will
|
||||
// cause all distributed cache to execute - which will clear out some caches we don't want.
|
||||
// http://issues.umbraco.org/issue/U4-3451
|
||||
|
||||
// when upgrading from 7.2 to 7.3 trying to save will throw
|
||||
if (UmbracoVersion.Current >= new Version(7, 3, 0, 0))
|
||||
MemberService.Save(member, false);
|
||||
{
|
||||
var now = DateTime.Now;
|
||||
// update the database data directly instead of a full member save which requires DB locks
|
||||
MemberService.SetLastLogin(username, now);
|
||||
member.LastLoginDate = now;
|
||||
member.UpdateDate = now;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ConvertToMembershipUser(member);
|
||||
@@ -555,6 +556,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
|
||||
var authenticated = CheckPassword(password, member.RawPasswordValue);
|
||||
|
||||
var requiresFullSave = false;
|
||||
|
||||
if (authenticated == false)
|
||||
{
|
||||
// TODO: Increment login attempts - lock if too many.
|
||||
@@ -574,6 +577,8 @@ namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>("Login attempt failed for username {Username} from IP address {IpAddress}", username, GetCurrentRequestIpAddress());
|
||||
}
|
||||
|
||||
requiresFullSave = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -581,6 +586,7 @@ namespace Umbraco.Web.Security.Providers
|
||||
{
|
||||
//we have successfully logged in, reset the AccessFailedCount
|
||||
member.FailedPasswordAttempts = 0;
|
||||
requiresFullSave = true;
|
||||
}
|
||||
|
||||
member.LastLoginDate = DateTime.Now;
|
||||
@@ -588,15 +594,23 @@ namespace Umbraco.Web.Security.Providers
|
||||
Current.Logger.Info<UmbracoMembershipProviderBase>("Login attempt succeeded for username {Username} from IP address {IpAddress}", username, GetCurrentRequestIpAddress());
|
||||
}
|
||||
|
||||
//don't raise events for this! It just sets the member dates, if we do raise events this will
|
||||
// don't raise events for this! It just sets the member dates, if we do raise events this will
|
||||
// cause all distributed cache to execute - which will clear out some caches we don't want.
|
||||
// http://issues.umbraco.org/issue/U4-3451
|
||||
// TODO: In v8 we aren't going to have an overload to disable events, so we'll need to make a different method
|
||||
// for this type of thing (i.e. UpdateLastLogin or similar).
|
||||
|
||||
// when upgrading from 7.2 to 7.3 trying to save will throw
|
||||
if (UmbracoVersion.Current >= new Version(7, 3, 0, 0))
|
||||
MemberService.Save(member, false);
|
||||
if (requiresFullSave)
|
||||
{
|
||||
// when upgrading from 7.2 to 7.3 trying to save will throw
|
||||
if (UmbracoVersion.Current >= new Version(7, 3, 0, 0))
|
||||
MemberService.Save(member, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// set the last login date without full save (fast, no locks)
|
||||
MemberService.SetLastLogin(member.Username, member.LastLoginDate);
|
||||
}
|
||||
|
||||
return new ValidateUserResult
|
||||
{
|
||||
|
||||
95
src/Umbraco.Web/Services/IconService.cs
Normal file
95
src/Umbraco.Web/Services/IconService.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Ganss.XSS;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Services
|
||||
{
|
||||
public class IconService : IIconService
|
||||
{
|
||||
private readonly IGlobalSettings _globalSettings;
|
||||
|
||||
public IconService(IGlobalSettings globalSettings)
|
||||
{
|
||||
_globalSettings = globalSettings;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public IList<IconModel> GetAllIcons()
|
||||
{
|
||||
var icons = new List<IconModel>();
|
||||
var directory = new DirectoryInfo(IOHelper.MapPath($"{_globalSettings.IconsPath}/"));
|
||||
var iconNames = directory.GetFiles("*.svg");
|
||||
|
||||
iconNames.OrderBy(f => f.Name).ToList().ForEach(iconInfo =>
|
||||
{
|
||||
var icon = GetIcon(iconInfo);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
icons.Add(icon);
|
||||
}
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IconModel GetIcon(string iconName)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(iconName)
|
||||
? null
|
||||
: CreateIconModel(iconName.StripFileExtension(), IOHelper.MapPath($"{_globalSettings.IconsPath}/{iconName}.svg"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IconModel using values from a FileInfo model
|
||||
/// </summary>
|
||||
/// <param name="fileInfo"></param>
|
||||
/// <returns></returns>
|
||||
private IconModel GetIcon(FileInfo fileInfo)
|
||||
{
|
||||
return fileInfo == null || string.IsNullOrWhiteSpace(fileInfo.Name)
|
||||
? null
|
||||
: CreateIconModel(fileInfo.Name.StripFileExtension(), fileInfo.FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an IconModel containing the icon name and SvgString
|
||||
/// </summary>
|
||||
/// <param name="iconName"></param>
|
||||
/// <param name="iconPath"></param>
|
||||
/// <returns></returns>
|
||||
private IconModel CreateIconModel(string iconName, string iconPath)
|
||||
{
|
||||
var sanitizer = new HtmlSanitizer();
|
||||
sanitizer.AllowedAttributes.UnionWith(Constants.SvgSanitizer.Attributes);
|
||||
sanitizer.AllowedCssProperties.UnionWith(Constants.SvgSanitizer.Attributes);
|
||||
sanitizer.AllowedTags.UnionWith(Constants.SvgSanitizer.Tags);
|
||||
|
||||
try
|
||||
{
|
||||
var svgContent = System.IO.File.ReadAllText(iconPath);
|
||||
var sanitizedString = sanitizer.Sanitize(svgContent);
|
||||
|
||||
var svg = new IconModel
|
||||
{
|
||||
Name = iconName,
|
||||
SvgString = sanitizedString
|
||||
};
|
||||
|
||||
return svg;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,7 +240,6 @@
|
||||
<Compile Include="Models\ContentEditing\LinkDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Models\IconModel.cs" />
|
||||
<Compile Include="Models\ContentEditing\UrlAndAnchors.cs" />
|
||||
<Compile Include="Models\ImageProcessorImageUrlGenerator.cs" />
|
||||
<Compile Include="Models\Mapping\CommonMapper.cs" />
|
||||
@@ -278,6 +277,7 @@
|
||||
<Compile Include="Routing\IPublishedRouter.cs" />
|
||||
<Compile Include="Routing\MediaUrlProviderCollection.cs" />
|
||||
<Compile Include="Routing\MediaUrlProviderCollectionBuilder.cs" />
|
||||
<Compile Include="Scheduling\SimpleTask.cs" />
|
||||
<Compile Include="Scheduling\TempFileCleanup.cs" />
|
||||
<Compile Include="Search\BackgroundIndexRebuilder.cs" />
|
||||
<Compile Include="Search\ExamineFinalComponent.cs" />
|
||||
@@ -291,6 +291,7 @@
|
||||
<Compile Include="Security\SignOutAuditEventArgs.cs" />
|
||||
<Compile Include="Security\UserInviteEventArgs.cs" />
|
||||
<Compile Include="Services\DashboardService.cs" />
|
||||
<Compile Include="Services\IconService.cs" />
|
||||
<Compile Include="Services\IDashboardService.cs" />
|
||||
<Compile Include="Models\Link.cs" />
|
||||
<Compile Include="Models\LinkType.cs" />
|
||||
|
||||
Reference in New Issue
Block a user