diff --git a/Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs b/Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs index 23971383..d1fc3e74 100644 --- a/Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs +++ b/Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs @@ -95,19 +95,15 @@ namespace Oqtane.Managers.Search searchContent.EntityName = EntityNames.Module; } - if(searchContent.EntityId == 0) + if(string.IsNullOrEmpty(searchContent.EntityId)) { - searchContent.EntityId = pageModule.ModuleId; + searchContent.EntityId = pageModule.ModuleId.ToString(); } - if (searchContent.IsActive) - { - searchContent.IsActive = !pageModule.Module.IsDeleted; - } - if (searchContent.ModifiedTime == DateTime.MinValue) + if (searchContent.ContentModifiedOn == DateTime.MinValue) { - searchContent.ModifiedTime = pageModule.ModifiedOn; + searchContent.ContentModifiedOn = pageModule.ModifiedOn; } if (string.IsNullOrEmpty(searchContent.AdditionalContent)) diff --git a/Oqtane.Server/Managers/Search/PageSearchIndexManager.cs b/Oqtane.Server/Managers/Search/PageSearchIndexManager.cs index 7e6e593c..9a74263b 100644 --- a/Oqtane.Server/Managers/Search/PageSearchIndexManager.cs +++ b/Oqtane.Server/Managers/Search/PageSearchIndexManager.cs @@ -48,16 +48,18 @@ namespace Oqtane.Managers.Search var searchContent = new SearchContent { - EntityName = EntityNames.Page, - EntityId = page.PageId, SiteId = page.SiteId, - ModifiedTime = page.ModifiedOn, - AdditionalContent = string.Empty, - Url = $"{(!string.IsNullOrEmpty(page.Path) && !page.Path.StartsWith("/") ? "/" : "")}{page.Path}", + EntityName = EntityNames.Page, + EntityId = page.PageId.ToString(), Title = !string.IsNullOrEmpty(page.Title) ? page.Title : page.Name, Description = string.Empty, Body = $"{page.Name} {page.Title}", - IsActive = !page.IsDeleted && Utilities.IsPageModuleVisible(page.EffectiveDate, page.ExpiryDate) + 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) diff --git a/Oqtane.Server/Migrations/EntityBuilders/SearchContentEntityBuilder.cs b/Oqtane.Server/Migrations/EntityBuilders/SearchContentEntityBuilder.cs index 4cf2aa4a..c8082c77 100644 --- a/Oqtane.Server/Migrations/EntityBuilders/SearchContentEntityBuilder.cs +++ b/Oqtane.Server/Migrations/EntityBuilders/SearchContentEntityBuilder.cs @@ -2,11 +2,10 @@ using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Migrations.Operations; using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders; using Oqtane.Databases.Interfaces; -using Oqtane.Models; namespace Oqtane.Migrations.EntityBuilders { - public class SearchContentEntityBuilder : AuditableBaseEntityBuilder + public class SearchContentEntityBuilder : BaseEntityBuilder { private const string _entityTableName = "SearchContent"; private readonly PrimaryKey _primaryKey = new("PK_SearchContent", x => x.SearchContentId); @@ -20,30 +19,30 @@ namespace Oqtane.Migrations.EntityBuilders protected override SearchContentEntityBuilder BuildTable(ColumnsBuilder table) { SearchContentId = AddAutoIncrementColumn(table, "SearchContentId"); + SiteId = AddIntegerColumn(table, "SiteId"); EntityName = AddStringColumn(table, "EntityName", 50); EntityId = AddIntegerColumn(table, "EntityId"); - SiteId = AddIntegerColumn(table, "SiteId"); - Title = AddStringColumn(table, "Title", 255); + Title = AddStringColumn(table, "Title", 200); Description = AddMaxStringColumn(table, "Description"); Body = AddMaxStringColumn(table, "Body"); - Url = AddStringColumn(table, "Url", 255); - ModifiedTime = AddDateTimeColumn(table, "ModifiedTime"); - IsActive = AddBooleanColumn(table, "IsActive"); + Url = AddStringColumn(table, "Url", 500); + Permissions = AddStringColumn(table, "Permissions", 100); + ContentModifiedBy = AddStringColumn(table, "ContentModifiedBy", 256); + ContentModifiedOn = AddDateTimeColumn(table, "ContentModifiedOn"); AdditionalContent = AddMaxStringColumn(table, "AdditionalContent"); - - AddAuditableColumns(table); + CreatedOn = AddDateTimeColumn(table, "CreatedOn"); return this; } public OperationBuilder SearchContentId { get; private set; } + public OperationBuilder SiteId { get; private set; } + public OperationBuilder EntityName { get; private set; } public OperationBuilder EntityId { get; private set; } - public OperationBuilder SiteId { get; private set; } - public OperationBuilder Title { get; private set; } public OperationBuilder Description { get; private set; } @@ -52,10 +51,14 @@ namespace Oqtane.Migrations.EntityBuilders public OperationBuilder Url { get; private set; } - public OperationBuilder ModifiedTime { get; private set; } + public OperationBuilder Permissions { get; private set; } - public OperationBuilder IsActive { get; private set; } + public OperationBuilder ContentModifiedBy { get; private set; } + + public OperationBuilder ContentModifiedOn { get; private set; } public OperationBuilder AdditionalContent { get; private set; } + + public OperationBuilder CreatedOn { get; private set; } } } diff --git a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs index 4c184e4b..7b5ecced 100644 --- a/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs +++ b/Oqtane.Server/Modules/HtmlText/Manager/HtmlTextManager.cs @@ -62,7 +62,8 @@ namespace Oqtane.Modules.HtmlText.Manager Title = module.Title, Description = string.Empty, Body = htmltext.Content, - ModifiedTime = htmltext.ModifiedOn + ContentModifiedBy = htmltext.ModifiedBy, + ContentModifiedOn = htmltext.ModifiedOn }); } diff --git a/Oqtane.Server/Providers/DatabaseSearchProvider.cs b/Oqtane.Server/Providers/DatabaseSearchProvider.cs index 3e09638b..3b8b037d 100644 --- a/Oqtane.Server/Providers/DatabaseSearchProvider.cs +++ b/Oqtane.Server/Providers/DatabaseSearchProvider.cs @@ -74,13 +74,13 @@ namespace Oqtane.Providers switch (searchQuery.SortField) { case SearchSortFields.Relevance: - results = results.OrderByDescending(i => i.Score).ThenByDescending(i => i.ModifiedTime); + results = results.OrderByDescending(i => i.Score).ThenByDescending(i => i.ContentModifiedOn); break; case SearchSortFields.Title: - results = results.OrderByDescending(i => i.Title).ThenByDescending(i => i.ModifiedTime); + results = results.OrderByDescending(i => i.Title).ThenByDescending(i => i.ContentModifiedOn); break; default: - results = results.OrderByDescending(i => i.ModifiedTime); + results = results.OrderByDescending(i => i.ContentModifiedOn); break; } } @@ -89,13 +89,13 @@ namespace Oqtane.Providers switch (searchQuery.SortField) { case SearchSortFields.Relevance: - results = results.OrderBy(i => i.Score).ThenByDescending(i => i.ModifiedTime); + results = results.OrderBy(i => i.Score).ThenByDescending(i => i.ContentModifiedOn); break; case SearchSortFields.Title: - results = results.OrderBy(i => i.Title).ThenByDescending(i => i.ModifiedTime); + results = results.OrderBy(i => i.Title).ThenByDescending(i => i.ContentModifiedOn); break; default: - results = results.OrderBy(i => i.ModifiedTime); + results = results.OrderBy(i => i.ContentModifiedOn); break; } } @@ -135,7 +135,9 @@ namespace Oqtane.Providers Description = searchContent.Description, Body = searchContent.Body, Url = searchContent.Url, - ModifiedTime = searchContent.ModifiedTime, + Permissions = searchContent.Permissions, + ContentModifiedBy = searchContent.ContentModifiedBy, + ContentModifiedOn = searchContent.ContentModifiedOn, SearchContentProperties = searchContent.SearchContentProperties, Snippet = BuildSnippet(searchContent, searchQuery), Score = CalculateScore(searchContent, searchQuery) diff --git a/Oqtane.Server/Repository/Interfaces/ISearchContentRepository.cs b/Oqtane.Server/Repository/Interfaces/ISearchContentRepository.cs index 38e3769c..8511b438 100644 --- a/Oqtane.Server/Repository/Interfaces/ISearchContentRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/ISearchContentRepository.cs @@ -10,7 +10,7 @@ namespace Oqtane.Repository Task> GetSearchContentsAsync(SearchQuery searchQuery); SearchContent AddSearchContent(SearchContent searchContent); void DeleteSearchContent(int searchContentId); - void DeleteSearchContent(string entityName, int entryId); + void DeleteSearchContent(string entityName, string entryId); void DeleteSearchContent(string uniqueKey); void DeleteAllSearchContent(); diff --git a/Oqtane.Server/Repository/SearchContentRepository.cs b/Oqtane.Server/Repository/SearchContentRepository.cs index 2d4c3bed..0f6071c5 100644 --- a/Oqtane.Server/Repository/SearchContentRepository.cs +++ b/Oqtane.Server/Repository/SearchContentRepository.cs @@ -24,7 +24,7 @@ namespace Oqtane.Repository .Include(i => i.SearchContentProperties) .Include(i => i.SearchContentWords) .ThenInclude(w => w.SearchWord) - .Where(i => i.SiteId == searchQuery.SiteId && i.IsActive); + .Where(i => i.SiteId == searchQuery.SiteId); if (searchQuery.EntityNames != null && searchQuery.EntityNames.Any()) { @@ -33,12 +33,12 @@ namespace Oqtane.Repository if (searchQuery.BeginModifiedTimeUtc != DateTime.MinValue) { - searchContents = searchContents.Where(i => i.ModifiedTime >= searchQuery.BeginModifiedTimeUtc); + searchContents = searchContents.Where(i => i.ContentModifiedOn >= searchQuery.BeginModifiedTimeUtc); } if (searchQuery.EndModifiedTimeUtc != DateTime.MinValue) { - searchContents = searchContents.Where(i => i.ModifiedTime <= searchQuery.EndModifiedTimeUtc); + searchContents = searchContents.Where(i => i.ContentModifiedOn <= searchQuery.EndModifiedTimeUtc); } if (searchQuery.Properties != null && searchQuery.Properties.Any()) @@ -88,7 +88,7 @@ namespace Oqtane.Repository db.SaveChanges(); } - public void DeleteSearchContent(string entityName, int entryId) + public void DeleteSearchContent(string entityName, string entryId) { using var db = _dbContextFactory.CreateDbContext(); var searchContent = db.SearchContent.FirstOrDefault(i => i.EntityName == entityName && i.EntityId == entryId); diff --git a/Oqtane.Server/Services/SearchService.cs b/Oqtane.Server/Services/SearchService.cs index f92757da..86a304be 100644 --- a/Oqtane.Server/Services/SearchService.cs +++ b/Oqtane.Server/Services/SearchService.cs @@ -10,6 +10,7 @@ using Oqtane.Models; using Oqtane.Repository; using Oqtane.Security; using Oqtane.Shared; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; namespace Oqtane.Services { @@ -199,17 +200,18 @@ namespace Oqtane.Services private bool Visible(SearchContent searchContent, SearchQuery searchQuery) { - if(!HasViewPermission(searchQuery.SiteId, searchQuery.User, searchContent.EntityName, searchContent.EntityId)) + var visible = true; + foreach (var permission in searchContent.Permissions.Split(',')) { - return false; + var entityName = permission.Split(":")[0]; + var entityId = int.Parse(permission.Split(":")[1]); + if (!HasViewPermission(searchQuery.SiteId, searchQuery.User, entityName, entityId)) + { + visible = false; + break; + } } - - var searchResultManager = GetSearchResultManagers().FirstOrDefault(i => i.Name == searchContent.EntityName); - if (searchResultManager != null) - { - return searchResultManager.Visible(searchContent, searchQuery); - } - return true; + return visible; } private bool HasViewPermission(int siteId, User user, string entityName, int entityId) diff --git a/Oqtane.Shared/Models/SearchContent.cs b/Oqtane.Shared/Models/SearchContent.cs index 2a242d7a..9a3c0cbe 100644 --- a/Oqtane.Shared/Models/SearchContent.cs +++ b/Oqtane.Shared/Models/SearchContent.cs @@ -4,18 +4,15 @@ using System.ComponentModel.DataAnnotations.Schema; using System.Text.Json; namespace Oqtane.Models { - public class SearchContent : ModelBase + public class SearchContent { public int SearchContentId { get; set; } - [NotMapped] - public string UniqueKey => $"{EntityName}:{EntityId}"; + public int SiteId { get; set; } public string EntityName { get; set; } - public int EntityId { get; set; } - - public int SiteId { get; set; } + public string EntityId { get; set; } public string Title { get; set; } @@ -25,16 +22,45 @@ namespace Oqtane.Models public string Url { get; set; } - public DateTime ModifiedTime { get; set; } + public string Permissions { get; set; } - public bool IsActive { get; set; } = true; + public string ContentModifiedBy { get; set; } + + public DateTime ContentModifiedOn { get; set; } public string AdditionalContent { get; set; } + public DateTime CreatedOn { get; set; } + public List SearchContentProperties { get; set; } public List SearchContentWords { get; set; } + [NotMapped] + public string UniqueKey => $"{EntityName}:{EntityId}"; + + [NotMapped] + public int TenantId { get; set; } + + // constructors + public SearchContent() { } + + public SearchContent(int siteId, string entityName, string entityId, string title, string description, string body, string url, string permissions, string contentModifiedBy, DateTime contentModifiedOn) + { + SiteId = siteId; + EntityName = entityName; + EntityId = entityId; + Title = title; + Description = description; + Body = body; + Url = url; + Permissions = permissions; + ContentModifiedBy = contentModifiedBy; + ContentModifiedOn = contentModifiedOn; + AdditionalContent = ""; + CreatedOn = DateTime.UtcNow; + } + public override string ToString() { return JsonSerializer.Serialize(this);