search refactoring
This commit is contained in:
parent
e321998b85
commit
5b46dd7293
|
@ -59,7 +59,7 @@ namespace Oqtane.Themes.Controls
|
|||
logouturl = Utilities.TenantUrl(PageState.Alias, "/pages/logout/");
|
||||
|
||||
// verify anonymous users can access current page
|
||||
if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate))
|
||||
if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsEffectiveOrExpired(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate))
|
||||
{
|
||||
returnurl = PageState.Route.PathAndQuery;
|
||||
}
|
||||
|
|
|
@ -254,7 +254,7 @@
|
|||
}
|
||||
|
||||
// check if user is authorized to view page
|
||||
if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
|
||||
if (page != null && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList) && (Utilities.IsEffectiveOrExpired(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList)))
|
||||
{
|
||||
// edit mode
|
||||
if (user != null)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Services;
|
||||
|
@ -11,7 +13,7 @@ namespace Oqtane.Infrastructure
|
|||
{
|
||||
public class SearchIndexJob : HostedServiceBase
|
||||
{
|
||||
private const string SearchIndexStartTimeSettingName = "SearchIndex_StartTime";
|
||||
private const string SearchLastIndexedOnSetting = "Search_LastIndexedOn";
|
||||
|
||||
public SearchIndexJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
|
||||
{
|
||||
|
@ -21,68 +23,231 @@ namespace Oqtane.Infrastructure
|
|||
IsEnabled = true;
|
||||
}
|
||||
|
||||
public override string ExecuteJob(IServiceProvider provider)
|
||||
public override async Task<string> ExecuteJobAsync(IServiceProvider provider)
|
||||
{
|
||||
string log = "";
|
||||
|
||||
// get services
|
||||
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||
var settingRepository = provider.GetRequiredService<ISettingRepository>();
|
||||
var logRepository = provider.GetRequiredService<ILogRepository>();
|
||||
var tenantManager = provider.GetRequiredService<ITenantManager>();
|
||||
var pageRepository = provider.GetRequiredService<IPageRepository>();
|
||||
var pageModuleRepository = provider.GetRequiredService<IPageModuleRepository>();
|
||||
var searchService = provider.GetRequiredService<ISearchService>();
|
||||
|
||||
var sites = siteRepository.GetSites().ToList();
|
||||
var logs = new StringBuilder();
|
||||
|
||||
foreach (var site in sites)
|
||||
{
|
||||
var startTime = GetSearchStartTime(site.SiteId, settingRepository);
|
||||
logs.AppendLine($"Search: Begin index site: {site.Name}<br />");
|
||||
log += $"Indexing Site: {site.Name}<br />";
|
||||
|
||||
// initialize
|
||||
var currentTime = DateTime.UtcNow;
|
||||
var lastIndexedOn = GetSearchLastIndexedOn(settingRepository, site.SiteId);
|
||||
var tenantId = tenantManager.GetTenant().TenantId;
|
||||
tenantManager.SetAlias(tenantId, site.SiteId);
|
||||
var pages = pageRepository.GetPages(site.SiteId);
|
||||
var pageModules = pageModuleRepository.GetPageModules(site.SiteId);
|
||||
var searchContents = new List<SearchContent>();
|
||||
|
||||
searchService.IndexContent(site.SiteId, startTime, logNote =>
|
||||
// index pages
|
||||
foreach (var page in pages)
|
||||
{
|
||||
logs.AppendLine(logNote);
|
||||
}, handleError =>
|
||||
if (Constants.InternalPagePaths.Contains(page.Path))
|
||||
{
|
||||
logs.AppendLine(handleError);
|
||||
});
|
||||
|
||||
UpdateSearchStartTime(site.SiteId, currentTime, settingRepository);
|
||||
|
||||
logs.AppendLine($"Search: End index site: {site.Name}<br />");
|
||||
continue;
|
||||
}
|
||||
|
||||
return logs.ToString();
|
||||
bool changed = false;
|
||||
bool removed = false;
|
||||
|
||||
if (page.ModifiedOn >= lastIndexedOn)
|
||||
{
|
||||
changed = true;
|
||||
removed = page.IsDeleted || !Utilities.IsEffectiveOrExpired(page.EffectiveDate, page.ExpiryDate);
|
||||
|
||||
var searchContent = new SearchContent
|
||||
{
|
||||
SiteId = page.SiteId,
|
||||
EntityName = EntityNames.Page,
|
||||
EntityId = page.PageId.ToString(),
|
||||
Title = !string.IsNullOrEmpty(page.Title) ? page.Title : page.Name,
|
||||
Description = string.Empty,
|
||||
Body = $"{page.Name} {page.Title}",
|
||||
Url = $"{(!string.IsNullOrEmpty(page.Path) && !page.Path.StartsWith("/") ? "/" : "")}{page.Path}",
|
||||
Permissions = $"{EntityNames.Page}:{page.PageId}",
|
||||
ContentModifiedBy = page.ModifiedBy,
|
||||
ContentModifiedOn = page.ModifiedOn,
|
||||
AdditionalContent = string.Empty,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
IsDeleted = removed,
|
||||
TenantId = tenantId
|
||||
};
|
||||
searchContents.Add(searchContent);
|
||||
}
|
||||
|
||||
private DateTime? GetSearchStartTime(int siteId, ISettingRepository settingRepository)
|
||||
// index modules
|
||||
foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchIndexStartTimeSettingName);
|
||||
if(setting == null)
|
||||
if (pageModule.ModifiedOn >= lastIndexedOn)
|
||||
{
|
||||
return null;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
var searchable = false;
|
||||
if (pageModule.Module.ModuleDefinition != null && pageModule.Module.ModuleDefinition.ServerManagerType != "")
|
||||
{
|
||||
Type type = Type.GetType(pageModule.Module.ModuleDefinition.ServerManagerType);
|
||||
if (type?.GetInterface(nameof(ISearchable)) != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
searchable = true;
|
||||
|
||||
// determine if reindexing is necessary
|
||||
var lastindexedon = (changed) ? DateTime.MinValue : lastIndexedOn;
|
||||
|
||||
// index module content
|
||||
var serverManager = (ISearchable)ActivatorUtilities.CreateInstance(provider, type);
|
||||
var searchcontents = await serverManager.GetSearchContentsAsync(pageModule, lastindexedon);
|
||||
if (searchcontents != null)
|
||||
{
|
||||
foreach (var searchContent in searchcontents)
|
||||
{
|
||||
SaveModuleMetaData(searchContent, pageModule, tenantId, removed);
|
||||
searchContents.Add(searchContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log += ex.Message + "<br />";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchable && changed)
|
||||
{
|
||||
// module does not implement ISearchable
|
||||
var searchContent = new SearchContent
|
||||
{
|
||||
SiteId = page.SiteId,
|
||||
EntityName = EntityNames.Module,
|
||||
EntityId = pageModule.ModuleId.ToString(),
|
||||
Title = pageModule.Title,
|
||||
Description = string.Empty,
|
||||
Body = $"{pageModule.Title}",
|
||||
Url = $"{(!string.IsNullOrEmpty(page.Path) && !page.Path.StartsWith("/") ? "/" : "")}{page.Path}",
|
||||
Permissions = $"{EntityNames.Module}:{pageModule.ModuleId},{EntityNames.Page}:{pageModule.PageId}",
|
||||
ContentModifiedBy = pageModule.ModifiedBy,
|
||||
ContentModifiedOn = pageModule.ModifiedOn,
|
||||
AdditionalContent = string.Empty,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
IsDeleted = (removed || pageModule.IsDeleted || !Utilities.IsEffectiveOrExpired(pageModule.EffectiveDate, pageModule.ExpiryDate)),
|
||||
TenantId = tenantId
|
||||
};
|
||||
searchContents.Add(searchContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// save search content
|
||||
await searchService.SaveSearchContentAsync(searchContents);
|
||||
log += $"Index Date: {lastIndexedOn}<br />";
|
||||
log += $"Items Indexed: {searchContents.Count}<br />";
|
||||
|
||||
// update last indexed on
|
||||
SaveSearchLastIndexedOn(settingRepository, site.SiteId, currentTime);
|
||||
}
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
|
||||
private void SaveModuleMetaData(SearchContent searchContent, PageModule pageModule, int tenantId, bool removed)
|
||||
{
|
||||
searchContent.SiteId = pageModule.Module.SiteId;
|
||||
searchContent.TenantId = tenantId;
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.EntityName))
|
||||
{
|
||||
searchContent.EntityName = EntityNames.Module;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.EntityId))
|
||||
{
|
||||
searchContent.EntityId = pageModule.ModuleId.ToString();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.Permissions))
|
||||
{
|
||||
searchContent.Permissions = $"{EntityNames.Module}:{pageModule.ModuleId},{EntityNames.Page}:{pageModule.PageId}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.ContentModifiedBy))
|
||||
{
|
||||
searchContent.ContentModifiedBy = pageModule.ModifiedBy;
|
||||
}
|
||||
|
||||
if (searchContent.ContentModifiedOn == DateTime.MinValue)
|
||||
{
|
||||
searchContent.ContentModifiedOn = pageModule.ModifiedOn;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.AdditionalContent))
|
||||
{
|
||||
searchContent.AdditionalContent = string.Empty;
|
||||
}
|
||||
|
||||
if (pageModule.Page != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchContent.Url))
|
||||
{
|
||||
searchContent.Url = $"{(!string.IsNullOrEmpty(pageModule.Page.Path) && !pageModule.Page.Path.StartsWith("/") ? "/" : "")}{pageModule.Page.Path}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.Title))
|
||||
{
|
||||
searchContent.Title = !string.IsNullOrEmpty(pageModule.Page.Title) ? pageModule.Page.Title : pageModule.Page.Name;
|
||||
}
|
||||
}
|
||||
|
||||
if (removed || pageModule.IsDeleted || !Utilities.IsEffectiveOrExpired(pageModule.EffectiveDate, pageModule.ExpiryDate))
|
||||
{
|
||||
searchContent.IsDeleted = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private DateTime GetSearchLastIndexedOn(ISettingRepository settingRepository, int siteId)
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchLastIndexedOnSetting);
|
||||
if (setting != null)
|
||||
{
|
||||
return Convert.ToDateTime(setting.SettingValue);
|
||||
}
|
||||
|
||||
private void UpdateSearchStartTime(int siteId, DateTime startTime, ISettingRepository settingRepository)
|
||||
else
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchIndexStartTimeSettingName);
|
||||
return DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveSearchLastIndexedOn(ISettingRepository settingRepository, int siteId, DateTime lastIndexedOn)
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchLastIndexedOnSetting);
|
||||
if (setting == null)
|
||||
{
|
||||
setting = new Setting
|
||||
{
|
||||
EntityName = EntityNames.Site,
|
||||
EntityId = siteId,
|
||||
SettingName = SearchIndexStartTimeSettingName,
|
||||
SettingValue = Convert.ToString(startTime),
|
||||
SettingName = SearchLastIndexedOnSetting,
|
||||
SettingValue = Convert.ToString(lastIndexedOn),
|
||||
};
|
||||
|
||||
settingRepository.AddSetting(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.SettingValue = Convert.ToString(startTime);
|
||||
setting.SettingValue = Convert.ToString(lastIndexedOn);
|
||||
settingRepository.UpdateSetting(setting);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Managers.Search
|
||||
{
|
||||
public class ModuleSearchIndexManager : SearchIndexManagerBase
|
||||
{
|
||||
public const int ModuleSearchIndexManagerPriority = 200;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ModuleSearchIndexManager> _logger;
|
||||
private readonly IPageModuleRepository _pageModuleRepostory;
|
||||
private readonly IPageRepository _pageRepository;
|
||||
|
||||
public ModuleSearchIndexManager(
|
||||
IServiceProvider serviceProvider,
|
||||
IPageModuleRepository pageModuleRepostory,
|
||||
ILogger<ModuleSearchIndexManager> logger,
|
||||
IPageRepository pageRepository)
|
||||
: base(serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_pageModuleRepostory = pageModuleRepostory;
|
||||
_pageRepository = pageRepository;
|
||||
}
|
||||
|
||||
public override string Name => EntityNames.Module;
|
||||
|
||||
public override int Priority => ModuleSearchIndexManagerPriority;
|
||||
|
||||
public override int IndexContent(int siteId, DateTime? startTime, Action<List<SearchContent>> processSearchContent, Action<string> handleError)
|
||||
{
|
||||
var pageModules = _pageModuleRepostory.GetPageModules(siteId).DistinctBy(i => i.ModuleId);
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
foreach(var pageModule in pageModules)
|
||||
{
|
||||
if(pageModule.Page == null || SearchUtils.IsSystemPage(pageModule.Page))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pageModule.Module.ModuleDefinition != null && pageModule.Module.ModuleDefinition.ServerManagerType != "")
|
||||
{
|
||||
_logger.LogDebug($"Search: Begin index module {pageModule.ModuleId}.");
|
||||
var type = Type.GetType(pageModule.Module.ModuleDefinition.ServerManagerType);
|
||||
if (type?.GetInterface(nameof(ISearchable)) != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var moduleSearch = (ISearchable)ActivatorUtilities.CreateInstance(_serviceProvider, type);
|
||||
var contentList = moduleSearch.GetSearchContents(pageModule, startTime.GetValueOrDefault(DateTime.MinValue));
|
||||
if(contentList != null)
|
||||
{
|
||||
foreach(var searchContent in contentList)
|
||||
{
|
||||
SaveModuleMetaData(searchContent, pageModule);
|
||||
|
||||
searchContentList.Add(searchContent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Search: Index module {pageModule.ModuleId} failed.");
|
||||
handleError($"Search: Index module {pageModule.ModuleId} failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
_logger.LogDebug($"Search: End index module {pageModule.ModuleId}.");
|
||||
}
|
||||
}
|
||||
|
||||
processSearchContent(searchContentList);
|
||||
|
||||
return searchContentList.Count;
|
||||
}
|
||||
|
||||
private void SaveModuleMetaData(SearchContent searchContent, PageModule pageModule)
|
||||
{
|
||||
searchContent.SiteId = pageModule.Module.SiteId;
|
||||
|
||||
if(string.IsNullOrEmpty(searchContent.EntityName))
|
||||
{
|
||||
searchContent.EntityName = EntityNames.Module;
|
||||
}
|
||||
|
||||
if(string.IsNullOrEmpty(searchContent.EntityId))
|
||||
{
|
||||
searchContent.EntityId = pageModule.ModuleId.ToString();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.Permissions))
|
||||
{
|
||||
searchContent.Permissions = $"{EntityNames.Module}:{pageModule.ModuleId},{EntityNames.Page}:{pageModule.PageId}";
|
||||
}
|
||||
|
||||
if (searchContent.ContentModifiedOn == DateTime.MinValue)
|
||||
{
|
||||
searchContent.ContentModifiedOn = pageModule.ModifiedOn;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.AdditionalContent))
|
||||
{
|
||||
searchContent.AdditionalContent = string.Empty;
|
||||
}
|
||||
|
||||
if (pageModule.Page != null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchContent.Url))
|
||||
{
|
||||
searchContent.Url = $"{(!string.IsNullOrEmpty(pageModule.Page.Path) && !pageModule.Page.Path.StartsWith("/") ? "/" : "")}{pageModule.Page.Path}";
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(searchContent.Title))
|
||||
{
|
||||
searchContent.Title = !string.IsNullOrEmpty(pageModule.Page.Title) ? pageModule.Page.Title : pageModule.Page.Name;
|
||||
}
|
||||
}
|
||||
|
||||
if (searchContent.SearchContentProperties == null)
|
||||
{
|
||||
searchContent.SearchContentProperties = new List<SearchContentProperty>();
|
||||
}
|
||||
|
||||
if(!searchContent.SearchContentProperties.Any(i => i.Name == Constants.SearchPageIdPropertyName))
|
||||
{
|
||||
searchContent.SearchContentProperties.Add(new SearchContentProperty { Name = Constants.SearchPageIdPropertyName, Value = pageModule.PageId.ToString() });
|
||||
}
|
||||
|
||||
if (!searchContent.SearchContentProperties.Any(i => i.Name == Constants.SearchModuleIdPropertyName))
|
||||
{
|
||||
searchContent.SearchContentProperties.Add(new SearchContentProperty { Name = Constants.SearchModuleIdPropertyName, Value = pageModule.ModuleId.ToString() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -54,7 +54,7 @@ namespace Oqtane.Managers.Search
|
|||
var page = pageRepository.GetPage(pageId);
|
||||
|
||||
return page != null && !page.IsDeleted && UserSecurity.IsAuthorized(user, PermissionNames.View, page.PermissionList)
|
||||
&& (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList));
|
||||
&& (Utilities.IsEffectiveOrExpired(page.EffectiveDate, page.ExpiryDate) || UserSecurity.IsAuthorized(user, PermissionNames.Edit, page.PermissionList));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,89 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Managers.Search
|
||||
{
|
||||
public class PageSearchIndexManager : SearchIndexManagerBase
|
||||
{
|
||||
private const int PageSearchIndexManagerPriority = 100;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ILogger<ModuleSearchIndexManager> _logger;
|
||||
private readonly IPageRepository _pageRepository;
|
||||
|
||||
public PageSearchIndexManager(
|
||||
IServiceProvider serviceProvider,
|
||||
ILogger<ModuleSearchIndexManager> logger,
|
||||
IPageRepository pageRepository)
|
||||
: base(serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_pageRepository = pageRepository;
|
||||
}
|
||||
|
||||
public override string Name => EntityNames.Page;
|
||||
|
||||
public override int Priority => PageSearchIndexManagerPriority;
|
||||
|
||||
public override int IndexContent(int siteId, DateTime? startTime, Action<List<SearchContent>> processSearchContent, Action<string> handleError)
|
||||
{
|
||||
var startTimeValue = startTime.GetValueOrDefault(DateTime.MinValue);
|
||||
var pages = _pageRepository.GetPages(siteId).Where(i => i.ModifiedOn >= startTimeValue);
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
foreach(var page in pages)
|
||||
{
|
||||
try
|
||||
{
|
||||
if(SearchUtils.IsSystemPage(page))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var searchContent = new SearchContent
|
||||
{
|
||||
SiteId = page.SiteId,
|
||||
EntityName = EntityNames.Page,
|
||||
EntityId = page.PageId.ToString(),
|
||||
Title = !string.IsNullOrEmpty(page.Title) ? page.Title : page.Name,
|
||||
Description = string.Empty,
|
||||
Body = $"{page.Name} {page.Title}",
|
||||
Url = $"{(!string.IsNullOrEmpty(page.Path) && !page.Path.StartsWith("/") ? "/" : "")}{page.Path}",
|
||||
Permissions = $"{EntityNames.Page}:{page.PageId}",
|
||||
ContentModifiedBy = page.ModifiedBy,
|
||||
ContentModifiedOn = page.ModifiedOn,
|
||||
AdditionalContent = string.Empty,
|
||||
CreatedOn = DateTime.UtcNow
|
||||
};
|
||||
|
||||
if (searchContent.SearchContentProperties == null)
|
||||
{
|
||||
searchContent.SearchContentProperties = new List<SearchContentProperty>();
|
||||
}
|
||||
|
||||
if (!searchContent.SearchContentProperties.Any(i => i.Name == Constants.SearchPageIdPropertyName))
|
||||
{
|
||||
searchContent.SearchContentProperties.Add(new SearchContentProperty { Name = Constants.SearchPageIdPropertyName, Value = page.PageId.ToString() });
|
||||
}
|
||||
|
||||
searchContentList.Add(searchContent);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Search: Index page {page.PageId} failed.");
|
||||
handleError($"Search: Index page {page.PageId} failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
processSearchContent(searchContentList);
|
||||
|
||||
return searchContentList.Count;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Managers.Search
|
||||
{
|
||||
public abstract class SearchIndexManagerBase : ISearchIndexManager
|
||||
{
|
||||
private const string SearchIndexManagerEnabledSettingFormat = "SearchIndexManager_{0}_Enabled";
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public SearchIndexManagerBase(IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public abstract int Priority { get; }
|
||||
|
||||
public abstract string Name { get; }
|
||||
|
||||
public abstract int IndexContent(int siteId, DateTime? startDate, Action<List<SearchContent>> processSearchContent, Action<string> handleError);
|
||||
|
||||
public virtual bool IsIndexEnabled(int siteId)
|
||||
{
|
||||
var settingName = string.Format(SearchIndexManagerEnabledSettingFormat, Name);
|
||||
var settingRepository = _serviceProvider.GetRequiredService<ISettingRepository>();
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, settingName);
|
||||
return setting == null || setting.SettingValue == "true";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ using System.Linq;
|
|||
using Oqtane.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
|
||||
|
@ -48,15 +49,18 @@ namespace Oqtane.Modules.HtmlText.Manager
|
|||
return content;
|
||||
}
|
||||
|
||||
public List<SearchContent> GetSearchContents(PageModule pageModule, DateTime startDate)
|
||||
public async Task<List<SearchContent>> GetSearchContentsAsync(PageModule pageModule, DateTime lastIndexedOn)
|
||||
{
|
||||
await Task.CompletedTask;
|
||||
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
var htmltexts = _htmlText.GetHtmlTexts(pageModule.ModuleId);
|
||||
if (htmltexts != null && htmltexts.Any(i => i.CreatedOn >= startDate))
|
||||
if (htmltexts != null && htmltexts.Any())
|
||||
{
|
||||
var htmltext = htmltexts.OrderByDescending(item => item.CreatedOn).First();
|
||||
|
||||
if (htmltext.CreatedOn >= lastIndexedOn)
|
||||
{
|
||||
searchContentList.Add(new SearchContent
|
||||
{
|
||||
Title = pageModule.Module.Title,
|
||||
|
@ -66,6 +70,7 @@ namespace Oqtane.Modules.HtmlText.Manager
|
|||
ContentModifiedOn = htmltext.ModifiedOn
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return searchContentList;
|
||||
}
|
||||
|
|
|
@ -46,16 +46,13 @@ namespace Oqtane.Pages
|
|||
{
|
||||
var sitemap = new List<Sitemap>();
|
||||
|
||||
// internal pages which should not be indexed
|
||||
string[] internalPaths = { "login", "register", "reset", "404" };
|
||||
|
||||
// build site map
|
||||
var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/")));
|
||||
var moduleDefinitions = _moduleDefinitions.GetModuleDefinitions(_alias.SiteId).ToList();
|
||||
var pageModules = _pageModules.GetPageModules(_alias.SiteId);
|
||||
foreach (var page in _pages.GetPages(_alias.SiteId))
|
||||
{
|
||||
if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && !internalPaths.Contains(page.Path))
|
||||
if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && !Constants.InternalPagePaths.Contains(page.Path))
|
||||
{
|
||||
var pageurl = rooturl;
|
||||
if (string.IsNullOrEmpty(page.Url))
|
||||
|
|
|
@ -46,9 +46,11 @@ namespace Oqtane.Providers
|
|||
|
||||
public void SaveSearchContent(SearchContent searchContent, bool autoCommit = false)
|
||||
{
|
||||
//remove exist document
|
||||
//remove existing search content
|
||||
_searchContentRepository.DeleteSearchContent(searchContent.EntityName, searchContent.EntityId);
|
||||
|
||||
if (!searchContent.IsDeleted)
|
||||
{
|
||||
//clean the search content to remove html tags
|
||||
CleanSearchContent(searchContent);
|
||||
|
||||
|
@ -57,6 +59,7 @@ namespace Oqtane.Providers
|
|||
//save the index words
|
||||
AnalyzeSearchContent(searchContent);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<SearchResults> SearchAsync(SearchQuery searchQuery, Func<SearchContent, SearchQuery, bool> validateFunc)
|
||||
{
|
||||
|
|
|
@ -44,45 +44,6 @@ namespace Oqtane.Services
|
|||
_cache = cache;
|
||||
}
|
||||
|
||||
public void IndexContent(int siteId, DateTime? startTime, Action<string> logNote, Action<string> handleError)
|
||||
{
|
||||
var searchEnabled = SearchEnabled(siteId);
|
||||
if(!searchEnabled)
|
||||
{
|
||||
logNote($"Search: Search is disabled on site {siteId}.<br />");
|
||||
return;
|
||||
}
|
||||
|
||||
_logger.LogDebug($"Search: Start Index Content of {siteId}, Start Time: {startTime.GetValueOrDefault(DateTime.MinValue)}");
|
||||
|
||||
var searchProvider = GetSearchProvider(siteId);
|
||||
|
||||
SetTenant(siteId);
|
||||
|
||||
if (startTime == null)
|
||||
{
|
||||
searchProvider.ResetIndex();
|
||||
}
|
||||
|
||||
var searchIndexManagers = GetSearchIndexManagers(m => { });
|
||||
foreach (var searchIndexManager in searchIndexManagers)
|
||||
{
|
||||
if (!searchIndexManager.IsIndexEnabled(siteId))
|
||||
{
|
||||
logNote($"Search: Ignore indexer {searchIndexManager.Name} because it's disabled.<br />");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.LogDebug($"Search: Begin Index {searchIndexManager.Name}");
|
||||
|
||||
var count = searchIndexManager.IndexContent(siteId, startTime, SaveSearchContent, handleError);
|
||||
logNote($"Search: Indexer {searchIndexManager.Name} processed {count} search content.<br />");
|
||||
|
||||
_logger.LogDebug($"Search: End Index {searchIndexManager.Name}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<SearchResults> SearchAsync(SearchQuery searchQuery)
|
||||
{
|
||||
var searchProvider = GetSearchProvider(searchQuery.SiteId);
|
||||
|
@ -141,23 +102,6 @@ namespace Oqtane.Services
|
|||
_tenantManager.SetAlias(alias);
|
||||
}
|
||||
|
||||
private List<ISearchIndexManager> GetSearchIndexManagers(Action<ISearchIndexManager> initManager)
|
||||
{
|
||||
var managers = new List<ISearchIndexManager>();
|
||||
var managerTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => typeof(ISearchIndexManager).IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract);
|
||||
|
||||
foreach (var type in managerTypes)
|
||||
{
|
||||
var manager = (ISearchIndexManager)ActivatorUtilities.CreateInstance(_serviceProvider, type);
|
||||
initManager(manager);
|
||||
managers.Add(manager);
|
||||
}
|
||||
|
||||
return managers.OrderBy(i => i.Priority).ToList();
|
||||
}
|
||||
|
||||
private List<ISearchResultManager> GetSearchResultManagers()
|
||||
{
|
||||
var managers = new List<ISearchResultManager>();
|
||||
|
@ -174,13 +118,13 @@ namespace Oqtane.Services
|
|||
return managers.ToList();
|
||||
}
|
||||
|
||||
private void SaveSearchContent(List<SearchContent> searchContentList)
|
||||
public async Task SaveSearchContentAsync(List<SearchContent> searchContents)
|
||||
{
|
||||
if(searchContentList.Any())
|
||||
if(searchContents.Any())
|
||||
{
|
||||
var searchProvider = GetSearchProvider(searchContentList.First().SiteId);
|
||||
var searchProvider = GetSearchProvider(searchContents.First().SiteId);
|
||||
|
||||
foreach (var searchContent in searchContentList)
|
||||
foreach (var searchContent in searchContents)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@ -192,6 +136,8 @@ namespace Oqtane.Services
|
|||
}
|
||||
}
|
||||
|
||||
await Task.CompletedTask;
|
||||
|
||||
//commit the index changes
|
||||
searchProvider.Commit();
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace Oqtane.Services
|
|||
var pages = new List<Page>();
|
||||
foreach (Page page in site.Pages)
|
||||
{
|
||||
if (!page.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, page.PermissionList) && (Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList)))
|
||||
if (!page.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, page.PermissionList) && (Utilities.IsEffectiveOrExpired(page.EffectiveDate, page.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList)))
|
||||
{
|
||||
pages.Add(page);
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ namespace Oqtane.Services
|
|||
var modules = new List<Module>();
|
||||
foreach (Module module in sitemodules.Where(item => (item.PageId == pageId || pageId == -1) && !item.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, item.PermissionList)))
|
||||
{
|
||||
if (Utilities.IsPageModuleVisible(module.EffectiveDate, module.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, module.PermissionList))
|
||||
if (Utilities.IsEffectiveOrExpired(module.EffectiveDate, module.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, module.PermissionList))
|
||||
{
|
||||
modules.Add(module);
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
public interface ISearchIndexManager
|
||||
{
|
||||
int Priority { get; }
|
||||
|
||||
string Name { get; }
|
||||
|
||||
bool IsIndexEnabled(int siteId);
|
||||
|
||||
int IndexContent(int siteId, DateTime? startTime, Action<List<SearchContent>> processSearchContent, Action<string> handleError);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
|
@ -8,7 +6,7 @@ namespace Oqtane.Services
|
|||
{
|
||||
public interface ISearchService
|
||||
{
|
||||
void IndexContent(int siteId, DateTime? startTime, Action<string> logNote, Action<string> handleError);
|
||||
Task SaveSearchContentAsync(List<SearchContent> searchContents);
|
||||
|
||||
Task<SearchResults> SearchAsync(SearchQuery searchQuery);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Interfaces
|
||||
{
|
||||
public interface ISearchable
|
||||
{
|
||||
public List<SearchContent> GetSearchContents(PageModule pageModule, DateTime startTime);
|
||||
public Task<List<SearchContent>> GetSearchContentsAsync(PageModule pageModule, DateTime lastIndexedOn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,6 +42,9 @@ namespace Oqtane.Models
|
|||
[NotMapped]
|
||||
public int TenantId { get; set; }
|
||||
|
||||
[NotMapped]
|
||||
public bool IsDeleted { get; set; }
|
||||
|
||||
// constructors
|
||||
public SearchContent() { }
|
||||
|
||||
|
|
|
@ -82,6 +82,8 @@ namespace Oqtane.Shared
|
|||
public const string SearchPageIdPropertyName = "PageId";
|
||||
public const string SearchModuleIdPropertyName = "ModuleId";
|
||||
|
||||
public static readonly string[] InternalPagePaths = { "login", "register", "reset", "404" };
|
||||
|
||||
// Obsolete constants
|
||||
|
||||
const string RoleObsoleteMessage = "Use the corresponding member from Oqtane.Shared.RoleNames";
|
||||
|
|
|
@ -560,7 +560,7 @@ namespace Oqtane.Shared
|
|||
|
||||
return (localDateTime?.Date, localTime);
|
||||
}
|
||||
public static bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate)
|
||||
public static bool IsEffectiveOrExpired(DateTime? effectiveDate, DateTime? expiryDate)
|
||||
{
|
||||
DateTime currentUtcTime = DateTime.UtcNow;
|
||||
|
||||
|
@ -582,6 +582,7 @@ namespace Oqtane.Shared
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate)
|
||||
{
|
||||
// Treat DateTime.MinValue as null
|
||||
|
@ -609,6 +610,7 @@ namespace Oqtane.Shared
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)]
|
||||
public static string ContentUrl(Alias alias, int fileId)
|
||||
{
|
||||
|
@ -623,5 +625,12 @@ namespace Oqtane.Shared
|
|||
|
||||
return $"{alias?.BaseUrl}{aliasUrl}{Constants.ContentUrl}{fileId}{method}";
|
||||
}
|
||||
|
||||
[Obsolete("IsPageModuleVisible(DateTime?, DateTime?) is deprecated. Use IsEffectiveOrExpired(DateTime?, DateTime?) instead.", false)]
|
||||
public static bool IsPageModuleVisible(DateTime? effectiveDate, DateTime? expiryDate)
|
||||
{
|
||||
return IsEffectiveOrExpired(effectiveDate, expiryDate);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user