Added a new dashboard to rebuild xml structures for content, members, media. I haven't put it in the release dashboard config for now. Also added methods to the examine controller to check the index integrity which we can use for th 7.3 task.
This commit is contained in:
@@ -0,0 +1,62 @@
|
||||
function xmlDataIntegrityReportController($scope, umbRequestHelper, $log, $http, $q, $timeout) {
|
||||
|
||||
function check(item) {
|
||||
var action = item.check;
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("xmlDataIntegrityBaseUrl", action)),
|
||||
'Failed to retrieve data integrity status')
|
||||
.then(function(result) {
|
||||
item.checking = false;
|
||||
item.invalid = result === "false";
|
||||
});
|
||||
}
|
||||
|
||||
$scope.fix = function(item) {
|
||||
var action = item.fix;
|
||||
if (item.fix) {
|
||||
if (confirm("This will cause all xml structures for this type to be rebuilt. " +
|
||||
"Depending on how much content there is in your site this could take a while. " +
|
||||
"It is not recommended to rebuild xml structures if they are not out of sync, during times of high website traffic " +
|
||||
"or when editors are editing content.")) {
|
||||
item.fixing = true;
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("xmlDataIntegrityBaseUrl", action)),
|
||||
'Failed to retrieve data integrity status')
|
||||
.then(function (result) {
|
||||
item.fixing = false;
|
||||
item.invalid = result === "false";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$scope.items = {
|
||||
"contentXml": {
|
||||
label: "Content in the cmsContentXml table",
|
||||
checking: true,
|
||||
fixing: false,
|
||||
fix: "FixContentXmlTable",
|
||||
check: "CheckContentXmlTable"
|
||||
},
|
||||
"mediaXml": {
|
||||
label: "Media in the cmsContentXml table",
|
||||
checking: true,
|
||||
fixing: false,
|
||||
fix: "FixMediaXmlTable",
|
||||
check: "CheckMediaXmlTable"
|
||||
},
|
||||
"memberXml": {
|
||||
label: "Members in the cmsContentXml table",
|
||||
checking: true,
|
||||
fixing: false,
|
||||
fix: "FixMembersXmlTable",
|
||||
check: "CheckMembersXmlTable"
|
||||
}
|
||||
};
|
||||
|
||||
for (var i in $scope.items) {
|
||||
check($scope.items[i]);
|
||||
}
|
||||
|
||||
}
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.XmlDataIntegrityReportController", xmlDataIntegrityReportController);
|
||||
@@ -0,0 +1,31 @@
|
||||
<div id="examineManagement" ng-controller="Umbraco.Dashboard.XmlDataIntegrityReportController">
|
||||
|
||||
<h3>Xml Cache Data integrity</h3>
|
||||
|
||||
<div ng-show="loading">
|
||||
Loading...
|
||||
</div>
|
||||
|
||||
<p>
|
||||
This checks the data integrity for the xml structures for content, media and members that are stored in the cmsContentXml table.
|
||||
This does not check the data integrity of the xml cache file, only the xml structures stored in the database used to create the xml cache file.
|
||||
</p>
|
||||
<div ng-repeat="(key, value) in items" class="umb-pane">
|
||||
<span class="">{{value.label}} ...</span>
|
||||
<span ng-if="value.checking" class="text-info">Checking...</span>
|
||||
<span ng-if="!value.checking && !value.invalid" class="text-success"><strong>Ok</strong></span>
|
||||
<span ng-if="!value.checking && value.invalid" class="text-error"><strong>Error</strong></span>
|
||||
<div ng-show="value.fix && !value.fixing">
|
||||
<button type="button" ng-click="fix(value)" class="btn btn-warning">
|
||||
<span ng-if="value.invalid">Fix</span>
|
||||
<span ng-if="!value.invalid">Rebuild</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="umb-loader-wrapper" ng-show="value.fixing">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -36,6 +36,11 @@
|
||||
views/dashboard/developer/examinemanagement.html
|
||||
</control>
|
||||
</tab>
|
||||
<tab caption="Xml Data Integrity Report">
|
||||
<control>
|
||||
views/dashboard/developer/xmldataintegrityreport.html
|
||||
</control>
|
||||
</tab>
|
||||
</section>
|
||||
<section alias="StartupMediaDashboardSection">
|
||||
<areas>
|
||||
|
||||
@@ -232,6 +232,10 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
"examineMgmtBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ExamineManagementApiController>(
|
||||
controller => controller.GetIndexerDetails())
|
||||
},
|
||||
{
|
||||
"xmlDataIntegrityBaseUrl", Url.GetUmbracoApiServiceBaseUrl<XmlDataIntegrityController>(
|
||||
controller => controller.CheckContentXmlTable())
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -9,9 +9,7 @@ using Umbraco.Core.IO;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// The API controller used for getting entity objects, basic name, icon, id representation of any umbraco object
|
||||
/// </summary>
|
||||
|
||||
[PluginController("UmbracoApi")]
|
||||
public class DashboardController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration.Dashboard;
|
||||
@@ -16,7 +17,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public static bool AuthorizeAccess(ISection dashboardSection, IUser user, ISectionService sectionService)
|
||||
{
|
||||
if (user.Id.ToString() == 0.ToInvariantString())
|
||||
if (user.Id.ToString(CultureInfo.InvariantCulture) == 0.ToInvariantString())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -30,7 +31,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public static bool AuthorizeAccess(IDashboardTab dashboardTab, IUser user, ISectionService sectionService)
|
||||
{
|
||||
if (user.Id.ToString() == Constants.System.Root.ToInvariantString())
|
||||
if (user.Id.ToString(CultureInfo.InvariantCulture) == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -44,7 +45,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
public static bool AuthorizeAccess(IDashboardControl dashboardTab, IUser user, ISectionService sectionService)
|
||||
{
|
||||
if (user.Id.ToString() == Constants.System.Root.ToInvariantString())
|
||||
if (user.Id.ToString(CultureInfo.InvariantCulture) == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -5,23 +5,14 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using Umbraco.Web.WebApi;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using Umbraco.Web.Models.TemplateQuery;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.Eventing.Reader;
|
||||
using System.Drawing;
|
||||
|
||||
using global::umbraco;
|
||||
using global::umbraco.cms.presentation;
|
||||
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using Umbraco.Web.Models.TemplateQuery;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
using Umbraco.Web.Models;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// The API controller used for building content queries within the template
|
||||
@@ -39,7 +30,7 @@ namespace Umbraco.Web.Editors
|
||||
{ }
|
||||
|
||||
|
||||
private static readonly IEnumerable<OperathorTerm> _terms = new List<OperathorTerm>()
|
||||
private static readonly IEnumerable<OperathorTerm> Terms = new List<OperathorTerm>()
|
||||
{
|
||||
new OperathorTerm("is", Operathor.Equals, new [] {"string"}),
|
||||
new OperathorTerm("is not", Operathor.NotEquals, new [] {"string"}),
|
||||
@@ -57,7 +48,7 @@ namespace Umbraco.Web.Editors
|
||||
new OperathorTerm("less than or equal to", Operathor.LessThanEqualTo, new [] {"int"})
|
||||
};
|
||||
|
||||
private static readonly IEnumerable<PropertyModel> _properties = new List<PropertyModel>()
|
||||
private static readonly IEnumerable<PropertyModel> Properties = new List<PropertyModel>()
|
||||
{
|
||||
new PropertyModel() { Name = "Id", Alias = "Id", Type = "int" },
|
||||
new PropertyModel() { Name = "Name", Alias = "Name", Type = "string" },
|
||||
@@ -309,7 +300,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
public IEnumerable<PropertyModel> GetAllowedProperties()
|
||||
{
|
||||
return _properties.OrderBy(x => x.Name);
|
||||
return Properties.OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -317,7 +308,7 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
public IEnumerable<object> GetFilterConditions()
|
||||
{
|
||||
return _terms;
|
||||
return Terms;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1863,6 +1863,7 @@
|
||||
<Compile Include="WebServices\UmbracoWebService.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="WebServices\XmlDataIntegrityController.cs" />
|
||||
<Compile Include="WebViewPageExtensions.cs" />
|
||||
<None Include="..\Umbraco.Web.UI\Views\web.config">
|
||||
<Link>Mvc\web.config</Link>
|
||||
|
||||
@@ -18,6 +18,54 @@ namespace Umbraco.Web.WebServices
|
||||
{
|
||||
public class ExamineManagementApiController : UmbracoAuthorizedApiController
|
||||
{
|
||||
/// <summary>
|
||||
/// Checks if the member internal index is consistent with the data stored in the database
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public bool CheckMembersInternalIndex()
|
||||
{
|
||||
var total = Services.MemberService.Count();
|
||||
|
||||
var criteria = ExamineManager.Instance.SearchProviderCollection["InternalMemberSearcher"]
|
||||
.CreateSearchCriteria().RawQuery("__IndexType:member");
|
||||
var totalIndexed = ExamineManager.Instance.SearchProviderCollection["InternalMemberSearcher"].Search(criteria);
|
||||
|
||||
return total == totalIndexed.TotalItemCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the media internal index is consistent with the data stored in the database
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public bool CheckMediaInternalIndex()
|
||||
{
|
||||
var total = Services.MediaService.Count();
|
||||
|
||||
var criteria = ExamineManager.Instance.SearchProviderCollection["InternalSearcher"]
|
||||
.CreateSearchCriteria().RawQuery("__IndexType:media");
|
||||
var totalIndexed = ExamineManager.Instance.SearchProviderCollection["InternalSearcher"].Search(criteria);
|
||||
|
||||
return total == totalIndexed.TotalItemCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the content internal index is consistent with the data stored in the database
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
[HttpGet]
|
||||
public bool CheckContentInternalIndex()
|
||||
{
|
||||
var total = Services.ContentService.Count();
|
||||
|
||||
var criteria = ExamineManager.Instance.SearchProviderCollection["InternalSearcher"]
|
||||
.CreateSearchCriteria().RawQuery("__IndexType:content");
|
||||
var totalIndexed = ExamineManager.Instance.SearchProviderCollection["InternalSearcher"].Search(criteria);
|
||||
|
||||
return total == totalIndexed.TotalItemCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the details for indexers
|
||||
/// </summary>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Examine;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.WebApi;
|
||||
|
||||
|
||||
82
src/Umbraco.Web/WebServices/XmlDataIntegrityController.cs
Normal file
82
src/Umbraco.Web/WebServices/XmlDataIntegrityController.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Web.Http;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Rdbms;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Web.WebApi;
|
||||
|
||||
namespace Umbraco.Web.WebServices
|
||||
{
|
||||
|
||||
public class XmlDataIntegrityController : UmbracoAuthorizedApiController
|
||||
{
|
||||
[HttpPost]
|
||||
public bool FixContentXmlTable()
|
||||
{
|
||||
Services.ContentService.RebuildXmlStructures();
|
||||
return CheckContentXmlTable();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public bool FixMediaXmlTable()
|
||||
{
|
||||
Services.MediaService.RebuildXmlStructures();
|
||||
return CheckMediaXmlTable();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public bool FixMembersXmlTable()
|
||||
{
|
||||
Services.MemberService.RebuildXmlStructures();
|
||||
return CheckMembersXmlTable();
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public bool CheckContentXmlTable()
|
||||
{
|
||||
var totalPublished = Services.ContentService.CountPublished();
|
||||
var subQuery = new Sql()
|
||||
.Select("Count(DISTINCT cmsContentXml.nodeId)")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<DocumentDto>()
|
||||
.On<DocumentDto, ContentXmlDto>(left => left.NodeId, right => right.NodeId);
|
||||
var totalXml = ApplicationContext.DatabaseContext.Database.ExecuteScalar<int>(subQuery);
|
||||
|
||||
return totalXml == totalPublished;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public bool CheckMediaXmlTable()
|
||||
{
|
||||
var total = Services.MediaService.Count();
|
||||
var mediaObjectType = Guid.Parse(Constants.ObjectTypes.Media);
|
||||
var subQuery = new Sql()
|
||||
.Select("Count(*)")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == mediaObjectType);
|
||||
var totalXml = ApplicationContext.DatabaseContext.Database.ExecuteScalar<int>(subQuery);
|
||||
|
||||
return totalXml == total;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public bool CheckMembersXmlTable()
|
||||
{
|
||||
var total = Services.MemberService.Count();
|
||||
var memberObjectType = Guid.Parse(Constants.ObjectTypes.Member);
|
||||
var subQuery = new Sql()
|
||||
.Select("Count(*)")
|
||||
.From<ContentXmlDto>()
|
||||
.InnerJoin<NodeDto>()
|
||||
.On<ContentXmlDto, NodeDto>(left => left.NodeId, right => right.NodeId)
|
||||
.Where<NodeDto>(dto => dto.NodeObjectType == memberObjectType);
|
||||
var totalXml = ApplicationContext.DatabaseContext.Database.ExecuteScalar<int>(subQuery);
|
||||
|
||||
return totalXml == total;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ namespace UmbracoExamine.DataServices
|
||||
/// <summary>
|
||||
/// Data service used to query for media
|
||||
/// </summary>
|
||||
[Obsolete("This should no longer be used, latest content will be indexed by using the IMediaService directly")]
|
||||
public class UmbracoMediaService : IMediaService
|
||||
{
|
||||
private readonly ServiceContext _services;
|
||||
@@ -39,7 +40,7 @@ namespace UmbracoExamine.DataServices
|
||||
/// </summary>
|
||||
/// <param name="xpath"></param>
|
||||
/// <returns></returns>
|
||||
|
||||
[Obsolete("This should no longer be used, latest content will be indexed by using the IMediaService directly")]
|
||||
public XDocument GetLatestMediaByXpath(string xpath)
|
||||
{
|
||||
var xmlMedia = XDocument.Parse("<media></media>");
|
||||
|
||||
Reference in New Issue
Block a user