Merge branch 'dev-v7.8' into temp-U4-10707
# Conflicts: # src/Umbraco.Web/Editors/TourController.cs # src/Umbraco.Web/Umbraco.Web.csproj
This commit is contained in:
@@ -532,6 +532,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[ContentPostValidate]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ContentItemDisplay PostSave(
|
||||
[ModelBinder(typeof(ContentItemBinder))]
|
||||
ContentItemSave contentItem)
|
||||
@@ -847,6 +848,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <param name="id"></param>
|
||||
/// <returns></returns>
|
||||
[EnsureUserPermissionForContent("id", 'U')]
|
||||
[OutgoingEditorModelEvent]
|
||||
public ContentItemDisplay PostUnPublish(int id)
|
||||
{
|
||||
var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id));
|
||||
|
||||
@@ -461,6 +461,7 @@ namespace Umbraco.Web.Editors
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[MediaPostValidate]
|
||||
[OutgoingEditorModelEvent]
|
||||
public MediaItemDisplay PostSave(
|
||||
[ModelBinder(typeof(MediaItemBinder))]
|
||||
MediaItemSave contentItem)
|
||||
|
||||
@@ -256,6 +256,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[FileUploadCleanupFilter]
|
||||
[OutgoingEditorModelEvent]
|
||||
public MemberDisplay PostSave(
|
||||
[ModelBinder(typeof(MemberBinder))]
|
||||
MemberSave contentItem)
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
@@ -18,29 +18,35 @@ namespace Umbraco.Web.Editors
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Content)]
|
||||
public class TourController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
public IEnumerable<Tour[]> GetTours()
|
||||
public IEnumerable<BackOfficeTourFile> GetTours()
|
||||
{
|
||||
var tours = new List<Tour[]>();
|
||||
var result = new List<BackOfficeTourFile>();
|
||||
|
||||
if (UmbracoConfig.For.UmbracoSettings().BackOffice.Tours.EnableTours == false)
|
||||
return tours;
|
||||
return result;
|
||||
|
||||
var toursPath = Path.Combine(IOHelper.MapPath(SystemDirectories.Config), "BackOfficeTours");
|
||||
if (Directory.Exists(toursPath) == false)
|
||||
return tours;
|
||||
return result;
|
||||
|
||||
var tourFiles = Directory.GetFiles(toursPath, "*.json")
|
||||
.OrderBy(x => x, StringComparer.InvariantCultureIgnoreCase);
|
||||
var disabledTours = TourFilterResolver.Current.DisabledTours;
|
||||
|
||||
var coreTourFiles = Directory.GetFiles(
|
||||
Path.Combine(IOHelper.MapPath(SystemDirectories.Config), "BackOfficeTours"), "*.json");
|
||||
|
||||
foreach (var tourFile in tourFiles)
|
||||
foreach (var tourFile in coreTourFiles)
|
||||
{
|
||||
try
|
||||
try
|
||||
{
|
||||
var contents = File.ReadAllText(tourFile);
|
||||
|
||||
result.Add(new BackOfficeTourFile
|
||||
{
|
||||
var contents = File.ReadAllText(tourFile);
|
||||
var tourArray = JsonConvert.DeserializeObject<Tour[]>(contents);
|
||||
tours.Add(tourArray.Where(x =>
|
||||
disabledTours.Contains(x.Alias, StringComparer.InvariantCultureIgnoreCase) == false).ToArray());
|
||||
FileName = Path.GetFileNameWithoutExtension(tourFile),
|
||||
Tours = JsonConvert.DeserializeObject<BackOfficeTour[]>(contents)
|
||||
});
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
@@ -52,9 +58,33 @@ namespace Umbraco.Web.Editors
|
||||
Logger.Error<TourController>("Error while trying to parse content as tour data: " + tourFile, e);
|
||||
throw new JsonReaderException("Error while trying to parse content as tour data: " + tourFile, e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tours;
|
||||
//collect all tour files in packges
|
||||
foreach (var plugin in Directory.EnumerateDirectories(IOHelper.MapPath(SystemDirectories.AppPlugins)))
|
||||
{
|
||||
var pluginName = Path.GetFileName(plugin.TrimEnd('\\'));
|
||||
|
||||
foreach (var backofficeDir in Directory.EnumerateDirectories(plugin, "backoffice"))
|
||||
{
|
||||
foreach (var tourDir in Directory.EnumerateDirectories(backofficeDir, "tours"))
|
||||
{
|
||||
foreach (var tourFile in Directory.EnumerateFiles(tourDir, "*.json"))
|
||||
{
|
||||
var contents = File.ReadAllText(tourFile);
|
||||
result.Add(new BackOfficeTourFile
|
||||
{
|
||||
FileName = Path.GetFileNameWithoutExtension(tourFile),
|
||||
PluginName = pluginName,
|
||||
Tours = JsonConvert.DeserializeObject<BackOfficeTour[]>(contents)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace Umbraco.Web
|
||||
private readonly List<BaseIndexProvider> _indexesToRebuild = new List<BaseIndexProvider>();
|
||||
private readonly ApplicationContext _appCtx;
|
||||
private readonly ProfilingLogger _profilingLogger;
|
||||
private static bool _isConfigured = false;
|
||||
|
||||
//this is used if we are not the MainDom, in which case we need to ensure that if indexes need rebuilding that this
|
||||
//doesn't occur since that should only occur when we are MainDom
|
||||
@@ -89,24 +90,7 @@ namespace Umbraco.Web
|
||||
/// </summary>
|
||||
public void Complete()
|
||||
{
|
||||
//We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending
|
||||
//indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because
|
||||
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
|
||||
foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType<LuceneIndexer>())
|
||||
{
|
||||
luceneIndexer.WaitForIndexQueueOnShutdown = false;
|
||||
|
||||
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
|
||||
//the indexes are not operational unless MainDom is true so if _disableExamineIndexing is false then we should be in charge
|
||||
if (_disableExamineIndexing == false)
|
||||
{
|
||||
var dir = luceneIndexer.GetLuceneDirectory();
|
||||
if (IndexWriter.IsLocked(dir))
|
||||
{
|
||||
IndexWriter.Unlock(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
EnsureUnlockedAndConfigured();
|
||||
|
||||
//Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them
|
||||
// (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually
|
||||
@@ -131,6 +115,8 @@ namespace Umbraco.Web
|
||||
//don't do anything if we have disabled this
|
||||
if (_disableExamineIndexing) return;
|
||||
|
||||
EnsureUnlockedAndConfigured();
|
||||
|
||||
//If the developer has explicitly opted out of rebuilding indexes on startup then we
|
||||
// should adhere to that and not do it, this means that if they are load balancing things will be
|
||||
// out of sync if they are auto-scaling but there's not much we can do about that.
|
||||
@@ -168,6 +154,40 @@ namespace Umbraco.Web
|
||||
yield return index;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Must be called to configure each index and ensure it's unlocked before any indexing occurs
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Indexing rebuilding can occur on a normal boot if the indexes are empty or on a cold boot by the database server messenger. Before
|
||||
/// either of these happens, we need to configure the indexes.
|
||||
/// </remarks>
|
||||
private void EnsureUnlockedAndConfigured()
|
||||
{
|
||||
if (_isConfigured) return;
|
||||
|
||||
_isConfigured = true;
|
||||
|
||||
foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType<LuceneIndexer>())
|
||||
{
|
||||
//We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending
|
||||
//indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because
|
||||
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
|
||||
luceneIndexer.WaitForIndexQueueOnShutdown = false;
|
||||
|
||||
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
|
||||
//the indexes are not operational unless MainDom is true so if _disableExamineIndexing is false then we should be in charge
|
||||
if (_disableExamineIndexing == false)
|
||||
{
|
||||
var dir = luceneIndexer.GetLuceneDirectory();
|
||||
if (IndexWriter.IsLocked(dir))
|
||||
{
|
||||
_profilingLogger.Logger.Info<ExamineStartup>("Forcing index " + luceneIndexer.IndexSetName + " to be unlocked since it was left in a locked state");
|
||||
IndexWriter.Unlock(dir);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args)
|
||||
{
|
||||
//store the indexer that needs rebuilding because it's empty for when the boot process
|
||||
|
||||
23
src/Umbraco.Web/Models/BackOfficeTour.cs
Normal file
23
src/Umbraco.Web/Models/BackOfficeTour.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
[DataContract(Name = "tour", Namespace = "")]
|
||||
public class BackOfficeTour
|
||||
{
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
[DataMember(Name = "group")]
|
||||
public string Group { get; set; }
|
||||
[DataMember(Name = "allowDisable")]
|
||||
public bool AllowDisable { get; set; }
|
||||
[DataMember(Name = "steps")]
|
||||
public BackOfficeTourStep[] Steps { get; set; }
|
||||
}
|
||||
}
|
||||
27
src/Umbraco.Web/Models/BackOfficeTourFile.cs
Normal file
27
src/Umbraco.Web/Models/BackOfficeTourFile.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
[DataContract(Name = "tourFile", Namespace = "")]
|
||||
public class BackOfficeTourFile
|
||||
{
|
||||
/// <summary>
|
||||
/// The file name for the tour
|
||||
/// </summary>
|
||||
[DataMember(Name = "fileName")]
|
||||
public string FileName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The plugin folder that the tour comes from
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If this is null it means it's a Core tour
|
||||
/// </remarks>
|
||||
[DataMember(Name = "pluginName")]
|
||||
public string PluginName { get; set; }
|
||||
|
||||
[DataMember(Name = "tours")]
|
||||
public IEnumerable<BackOfficeTour> Tours { get; set; }
|
||||
}
|
||||
}
|
||||
23
src/Umbraco.Web/Models/BackOfficeTourStep.cs
Normal file
23
src/Umbraco.Web/Models/BackOfficeTourStep.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
[DataContract(Name = "step", Namespace = "")]
|
||||
public class BackOfficeTourStep
|
||||
{
|
||||
[DataMember(Name = "title")]
|
||||
public string Title { get; set; }
|
||||
[DataMember(Name = "content")]
|
||||
public string Content { get; set; }
|
||||
[DataMember(Name = "type")]
|
||||
public string Type { get; set; }
|
||||
[DataMember(Name = "element")]
|
||||
public string Element { get; set; }
|
||||
[DataMember(Name = "elementPreventClick")]
|
||||
public bool ElementPreventClick { get; set; }
|
||||
[DataMember(Name = "backdropOpacity")]
|
||||
public float BackdropOpacity { get; set; }
|
||||
[DataMember(Name = "event")]
|
||||
public string Event { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -251,7 +251,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
|
||||
// move to parent node
|
||||
e = (XmlElement) e.ParentNode;
|
||||
id = int.Parse(e.GetAttribute("id"));
|
||||
id = int.Parse(e.GetAttribute("id"), CultureInfo.InvariantCulture);
|
||||
hasDomains = id != -1 && domainHelper.NodeHasDomains(id);
|
||||
}
|
||||
|
||||
|
||||
@@ -230,7 +230,7 @@ namespace Umbraco.Web
|
||||
{
|
||||
// todo: in v8, implement in a more efficient way
|
||||
var legacyXml = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema;
|
||||
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@isDoc and @key=$guid]";
|
||||
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@key=$guid]";
|
||||
var doc = cache.GetSingleByXPath(xpath, new XPathVariable("guid", id.ToString()));
|
||||
return doc;
|
||||
}
|
||||
|
||||
@@ -372,6 +372,8 @@
|
||||
<Compile Include="HealthCheck\Checks\DataIntegrity\XmlDataIntegrityHealthCheck.cs" />
|
||||
<Compile Include="IHttpContextAccessor.cs" />
|
||||
<Compile Include="Install\InstallSteps\ConfigureMachineKey.cs" />
|
||||
<Compile Include="Models\BackOfficeTourFile.cs" />
|
||||
<Compile Include="Models\BackOfficeTourStep.cs" />
|
||||
<Compile Include="Models\ContentEditing\AssignedContentPermissions.cs" />
|
||||
<Compile Include="Models\ContentEditing\AssignedUserGroupPermissions.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentRedirectUrl.cs" />
|
||||
@@ -430,6 +432,7 @@
|
||||
<Compile Include="Models\RequestPasswordResetModel.cs" />
|
||||
<Compile Include="Models\PublishedContentWithKeyBase.cs" />
|
||||
<Compile Include="Models\Tour.cs" />
|
||||
<Compile Include="Models\BackOfficeTour.cs" />
|
||||
<Compile Include="Models\TourStep.cs" />
|
||||
<Compile Include="Models\UserTourStatus.cs" />
|
||||
<Compile Include="Models\ValidatePasswordResetCodeModel.cs" />
|
||||
|
||||
Reference in New Issue
Block a user