Merge remote-tracking branch 'oqtane/dev' into dev
This commit is contained in:
@ -16,6 +16,7 @@
|
||||
@using Oqtane.Shared
|
||||
@using Oqtane.Themes
|
||||
@using Oqtane.Extensions
|
||||
@using System.Globalization
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IAntiforgery Antiforgery
|
||||
@inject IConfigManager ConfigManager
|
||||
@ -39,7 +40,7 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<base href="/" />
|
||||
<link rel="stylesheet" href="css/app.css" />
|
||||
@if (!string.IsNullOrEmpty(_PWAScript))
|
||||
@if (_scripts.Contains("PWA Manifest"))
|
||||
{
|
||||
<link id="app-manifest" rel="manifest" />
|
||||
}
|
||||
@ -68,20 +69,13 @@
|
||||
<Routes PageState="@_pageState" RenderMode="@_renderMode" Runtime="@_runtime" AntiForgeryToken="@_antiForgeryToken" AuthorizationToken="@_authorizationToken" Platform="@_platform" @rendermode="InteractiveRenderMode.GetInteractiveRenderMode(_runtime, _prerender)" />
|
||||
}
|
||||
|
||||
@if (!string.IsNullOrEmpty(_reconnectScript))
|
||||
{
|
||||
@((MarkupString)_reconnectScript)
|
||||
}
|
||||
@if (!string.IsNullOrEmpty(_PWAScript))
|
||||
{
|
||||
@((MarkupString)_PWAScript)
|
||||
}
|
||||
@((MarkupString)_bodyResources)
|
||||
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
<script src="js/app.js"></script>
|
||||
<script src="js/loadjs.min.js"></script>
|
||||
<script src="js/interop.js"></script>
|
||||
<script src="_framework/blazor.web.js"></script>
|
||||
|
||||
@((MarkupString)_scripts)
|
||||
@((MarkupString)_bodyResources)
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -105,8 +99,7 @@
|
||||
private string _headResources = "";
|
||||
private string _bodyResources = "";
|
||||
private string _styleSheets = "";
|
||||
private string _PWAScript = "";
|
||||
private string _reconnectScript = "";
|
||||
private string _scripts = "";
|
||||
private string _message = "";
|
||||
private PageState _pageState;
|
||||
|
||||
@ -139,6 +132,7 @@
|
||||
_renderMode = site.RenderMode;
|
||||
_runtime = site.Runtime;
|
||||
_prerender = site.Prerender;
|
||||
var modules = new List<Module>();
|
||||
|
||||
Route route = new Route(url, alias.Path);
|
||||
var page = site.Pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
|
||||
@ -163,6 +157,10 @@
|
||||
{
|
||||
HandlePageNotFound(site, page, route);
|
||||
}
|
||||
else
|
||||
{
|
||||
modules = await SiteService.GetModulesAsync(site.SiteId, page.PageId);
|
||||
}
|
||||
|
||||
if (site.VisitorTracking)
|
||||
{
|
||||
@ -175,23 +173,25 @@
|
||||
CreateJwtToken(alias);
|
||||
}
|
||||
|
||||
// include stylesheets to prevent FOUC
|
||||
var resources = GetPageResources(alias, site, page, int.Parse(route.ModuleId), route.Action);
|
||||
// includes resources
|
||||
var resources = await GetPageResources(alias, site, page, modules, int.Parse(route.ModuleId, CultureInfo.InvariantCulture), route.Action);
|
||||
ManageStyleSheets(resources);
|
||||
ManageScripts(resources, alias);
|
||||
|
||||
// scripts
|
||||
if (_renderMode == RenderModes.Static)
|
||||
{
|
||||
ManageScripts(resources, alias);
|
||||
}
|
||||
// generate scripts
|
||||
if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server)
|
||||
{
|
||||
_reconnectScript = CreateReconnectScript();
|
||||
_scripts += CreateReconnectScript();
|
||||
}
|
||||
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
||||
{
|
||||
_PWAScript = CreatePWAScript(alias, site, route);
|
||||
_scripts += CreatePWAScript(alias, site, route);
|
||||
}
|
||||
@if (_renderMode == RenderModes.Static)
|
||||
{
|
||||
_scripts += CreateScrollPositionScript();
|
||||
}
|
||||
|
||||
_headResources += ParseScripts(site.HeadContent);
|
||||
_bodyResources += ParseScripts(site.BodyContent);
|
||||
|
||||
@ -220,12 +220,13 @@
|
||||
_language = _language.Replace("c=", "");
|
||||
}
|
||||
|
||||
// create initial PageState
|
||||
// create initial PageState
|
||||
_pageState = new PageState
|
||||
{
|
||||
Alias = alias,
|
||||
Site = site,
|
||||
Page = page,
|
||||
Modules = modules,
|
||||
User = null,
|
||||
Uri = new Uri(url, UriKind.Absolute),
|
||||
Route = route,
|
||||
@ -329,14 +330,26 @@
|
||||
int? userid = Context.User.UserId();
|
||||
userid = (userid == -1) ? null : userid;
|
||||
|
||||
// check if cookie already exists
|
||||
// get cookie value
|
||||
var visitorCookieName = Constants.VisitorCookiePrefix + SiteId.ToString();
|
||||
var visitorCookieValue = Context.Request.Cookies[visitorCookieName];
|
||||
DateTime expiry = DateTime.MinValue;
|
||||
if (visitorCookieValue != null && visitorCookieValue.Contains("|"))
|
||||
{
|
||||
var values = visitorCookieValue.Split('|');
|
||||
int.TryParse(values[0], out _visitorId);
|
||||
DateTime.TryParseExact(values[1], "M/d/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture, DateTimeStyles.None, out expiry);
|
||||
}
|
||||
else // legacy cookie format
|
||||
{
|
||||
int.TryParse(visitorCookieValue, out _visitorId);
|
||||
}
|
||||
bool setcookie = false;
|
||||
Visitor visitor = null;
|
||||
bool addcookie = false;
|
||||
var VisitorCookie = Constants.VisitorCookiePrefix + SiteId.ToString();
|
||||
if (!int.TryParse(Context.Request.Cookies[VisitorCookie], out _visitorId))
|
||||
|
||||
if (_visitorId <= 0)
|
||||
{
|
||||
// if enabled use IP Address correlation
|
||||
_visitorId = -1;
|
||||
var correlate = bool.Parse(settings.GetValue("VisitorCorrelation", "true"));
|
||||
if (correlate)
|
||||
{
|
||||
@ -344,12 +357,12 @@
|
||||
if (visitor != null)
|
||||
{
|
||||
_visitorId = visitor.VisitorId;
|
||||
addcookie = true;
|
||||
setcookie = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_visitorId == -1)
|
||||
if (_visitorId <= 0)
|
||||
{
|
||||
// create new visitor
|
||||
visitor = new Visitor();
|
||||
@ -365,52 +378,59 @@
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
visitor = VisitorRepository.AddVisitor(visitor);
|
||||
_visitorId = visitor.VisitorId;
|
||||
addcookie = true;
|
||||
setcookie = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (visitor == null)
|
||||
// check expiry
|
||||
if (DateTime.UtcNow > expiry)
|
||||
{
|
||||
// get visitor if it was not previously loaded
|
||||
visitor = VisitorRepository.GetVisitor(_visitorId);
|
||||
}
|
||||
if (visitor != null)
|
||||
{
|
||||
// update visitor
|
||||
visitor.IPAddress = _remoteIPAddress;
|
||||
visitor.UserAgent = useragent;
|
||||
visitor.Language = language;
|
||||
visitor.Url = url;
|
||||
if (!string.IsNullOrEmpty(referrer))
|
||||
if (visitor == null)
|
||||
{
|
||||
visitor.Referrer = referrer;
|
||||
// get visitor if not previously loaded
|
||||
visitor = VisitorRepository.GetVisitor(_visitorId);
|
||||
}
|
||||
if (userid != null)
|
||||
if (visitor != null)
|
||||
{
|
||||
visitor.UserId = userid;
|
||||
// update visitor
|
||||
visitor.IPAddress = _remoteIPAddress;
|
||||
visitor.UserAgent = useragent;
|
||||
visitor.Language = language;
|
||||
visitor.Url = url;
|
||||
if (!string.IsNullOrEmpty(referrer))
|
||||
{
|
||||
visitor.Referrer = referrer;
|
||||
}
|
||||
if (userid != null)
|
||||
{
|
||||
visitor.UserId = userid;
|
||||
}
|
||||
visitor.Visits += 1;
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
VisitorRepository.UpdateVisitor(visitor);
|
||||
setcookie = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove cookie if visitor does not exist
|
||||
Context.Response.Cookies.Delete(visitorCookieName);
|
||||
}
|
||||
visitor.Visits += 1;
|
||||
visitor.VisitedOn = DateTime.UtcNow;
|
||||
VisitorRepository.UpdateVisitor(visitor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove cookie if VisitorId does not exist
|
||||
Context.Response.Cookies.Delete(VisitorCookie);
|
||||
}
|
||||
}
|
||||
|
||||
// append cookie
|
||||
if (addcookie)
|
||||
// set cookie
|
||||
if (setcookie)
|
||||
{
|
||||
expiry = DateTime.UtcNow.AddMinutes(int.Parse(settings.GetValue("VisitorDuration", "5")));
|
||||
|
||||
Context.Response.Cookies.Append(
|
||||
VisitorCookie,
|
||||
_visitorId.ToString(),
|
||||
visitorCookieName,
|
||||
$"{_visitorId}|{expiry.ToString("M/d/yyyy hh:mm:ss tt", CultureInfo.InvariantCulture)}",
|
||||
new CookieOptions()
|
||||
{
|
||||
Expires = DateTimeOffset.UtcNow.AddYears(1),
|
||||
IsEssential = true
|
||||
}
|
||||
{
|
||||
Expires = DateTimeOffset.UtcNow.AddYears(10),
|
||||
IsEssential = true
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -432,7 +452,7 @@
|
||||
|
||||
private string CreatePWAScript(Alias alias, Site site, Route route)
|
||||
{
|
||||
return
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // PWA Manifest" + Environment.NewLine +
|
||||
" setTimeout(() => {" + Environment.NewLine +
|
||||
@ -468,14 +488,14 @@
|
||||
" console.log('ServiceWorker Registration Failed ', err);" + Environment.NewLine +
|
||||
" });" + Environment.NewLine +
|
||||
" };" + Environment.NewLine +
|
||||
"</script>";
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string CreateReconnectScript()
|
||||
{
|
||||
return
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // Blazor Server Reconnect" + Environment.NewLine +
|
||||
" // Interactive Blazor Server Reconnect" + Environment.NewLine +
|
||||
" new MutationObserver((mutations, observer) => {" + Environment.NewLine +
|
||||
" if (document.querySelector('#components-reconnect-modal h5 a')) {" + Environment.NewLine +
|
||||
" async function attemptReload() {" + Environment.NewLine +
|
||||
@ -487,7 +507,26 @@
|
||||
" setInterval(attemptReload, 5000);" + Environment.NewLine +
|
||||
" }" + Environment.NewLine +
|
||||
" }).observe(document.body, { childList: true, subtree: true });" + Environment.NewLine +
|
||||
"</script>";
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string CreateScrollPositionScript()
|
||||
{
|
||||
return Environment.NewLine +
|
||||
"<script>" + Environment.NewLine +
|
||||
" // Blazor Static Rendering Scroll Position" + Environment.NewLine +
|
||||
" window.interceptNavigation = () => {" + Environment.NewLine +
|
||||
" let currentUrl = window.location.href;" + Environment.NewLine +
|
||||
" Blazor.addEventListener('enhancedload', () => {" + Environment.NewLine +
|
||||
" let newUrl = window.location.href;" + Environment.NewLine +
|
||||
" if (currentUrl != newUrl) {" + Environment.NewLine +
|
||||
" window.scrollTo({ top: 0, left: 0, behavior: 'instant' });" + Environment.NewLine +
|
||||
" }" + Environment.NewLine +
|
||||
" currentUrl = newUrl;" + Environment.NewLine +
|
||||
" });" + Environment.NewLine +
|
||||
" };" + Environment.NewLine +
|
||||
" document.onload += window.interceptNavigation();" + Environment.NewLine +
|
||||
"</script>" + Environment.NewLine;
|
||||
}
|
||||
|
||||
private string ParseScripts(string content)
|
||||
@ -536,7 +575,7 @@
|
||||
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
||||
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
|
||||
((resource.ES6Module) ? " type=\"module\"" : "") +
|
||||
" src =\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm
|
||||
" src=\"" + url + "\"></script>"; // src at end of element due to enhanced navigation patch algorithm
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -558,7 +597,7 @@
|
||||
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)));
|
||||
}
|
||||
|
||||
private List<Resource> GetPageResources(Alias alias, Site site, Page page, int moduleid, string action)
|
||||
private async Task<List<Resource>> GetPageResources(Alias alias, Site site, Page page, List<Module> modules, int moduleid, string action)
|
||||
{
|
||||
var resources = new List<Resource>();
|
||||
|
||||
@ -566,13 +605,13 @@
|
||||
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType));
|
||||
if (theme != null)
|
||||
{
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), site.RenderMode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fallback to default Oqtane theme
|
||||
theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == Constants.DefaultTheme));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), site.RenderMode);
|
||||
}
|
||||
var type = Type.GetType(themeType);
|
||||
if (type != null)
|
||||
@ -580,16 +619,16 @@
|
||||
var obj = Activator.CreateInstance(type) as IThemeControl;
|
||||
if (obj != null)
|
||||
{
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace, site.RenderMode);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Module module in site.Modules.Where(item => item.PageId == page.PageId || item.ModuleId == moduleid))
|
||||
foreach (Module module in modules.Where(item => item.PageId == page.PageId || item.ModuleId == moduleid))
|
||||
{
|
||||
var typename = "";
|
||||
if (module.ModuleDefinition != null)
|
||||
{
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), site.RenderMode);
|
||||
|
||||
// handle default action
|
||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||
@ -635,7 +674,7 @@
|
||||
var obj = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
if (obj != null)
|
||||
{
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||
{
|
||||
// settings components are embedded within a framework settings module
|
||||
@ -643,45 +682,51 @@
|
||||
if (moduletype != null)
|
||||
{
|
||||
obj = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// site level resources for modules in site
|
||||
var modules = site.Modules.GroupBy(item => item.ModuleDefinition?.ModuleDefinitionName).Select(group => group.First()).ToList();
|
||||
foreach (var module in modules)
|
||||
if (site.RenderMode == RenderModes.Interactive)
|
||||
{
|
||||
if (module.ModuleDefinition?.Resources != null)
|
||||
// site level resources for modules in site
|
||||
var sitemodules = await SiteService.GetModulesAsync(site.SiteId, -1);
|
||||
foreach (var module in sitemodules.GroupBy(item => item.ModuleDefinition?.ModuleDefinitionName).Select(group => group.First()).ToList())
|
||||
{
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources.Where(item => item.Level == ResourceLevel.Site).ToList(), ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
||||
if (module.ModuleDefinition?.Resources != null)
|
||||
{
|
||||
resources = AddResources(resources, module.ModuleDefinition.Resources.Where(item => item.ResourceType == ResourceType.Script && item.Level == ResourceLevel.Site).ToList(), ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), site.RenderMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resources;
|
||||
}
|
||||
|
||||
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name)
|
||||
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name, string rendermode)
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
foreach (var resource in resources)
|
||||
{
|
||||
if (resource.Url.StartsWith("~"))
|
||||
if (rendermode == RenderModes.Static || resource.ResourceType == ResourceType.Stylesheet || resource.Level == ResourceLevel.Site)
|
||||
{
|
||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||
}
|
||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||
{
|
||||
resource.Url = alias.BaseUrl + resource.Url;
|
||||
}
|
||||
if (resource.Url.StartsWith("~"))
|
||||
{
|
||||
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||
}
|
||||
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||
{
|
||||
resource.Url = alias.BaseUrl + resource.Url;
|
||||
}
|
||||
|
||||
// ensure resource does not exist already
|
||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||
{
|
||||
pageresources.Add(resource.Clone(level, name));
|
||||
// ensure resource does not exist already
|
||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||
{
|
||||
pageresources.Add(resource.Clone(level, name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -692,6 +737,7 @@
|
||||
{
|
||||
if (resources != null)
|
||||
{
|
||||
// include stylesheets to prevent FOUC
|
||||
string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff");
|
||||
int count = 0;
|
||||
foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet))
|
||||
|
16
Oqtane.Server/Components/_Placeholder.cs
Normal file
16
Oqtane.Server/Components/_Placeholder.cs
Normal file
@ -0,0 +1,16 @@
|
||||
// This is just a placeholder file
|
||||
// It is necessary for the documentation to successfully build this project.
|
||||
// Reason is that docfx will run the .net compiler and find references
|
||||
// to this class in the project.
|
||||
// But since the real class is just a .razor file, ATM docfx will fail.
|
||||
//
|
||||
// Note added 2024-06-27 by @iJungleboy.
|
||||
// We hope that as .net and docfx improve, the razor-compiler will work in that scenario
|
||||
// as well, and this file can be removed.
|
||||
|
||||
using Oqtane.Documentation;
|
||||
|
||||
namespace Oqtane.Components;
|
||||
|
||||
[PrivateApi]
|
||||
public class _Placeholder;
|
@ -760,7 +760,7 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
if (!Directory.Exists(folderpath))
|
||||
{
|
||||
string path = "";
|
||||
string path = folderpath.StartsWith(Path.DirectorySeparatorChar) ? Path.DirectorySeparatorChar.ToString() : string.Empty;
|
||||
var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
|
||||
string[] folders = folderpath.Split(separators, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (string folder in folders)
|
||||
|
@ -76,5 +76,20 @@ namespace Oqtane.Controllers
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete]
|
||||
[Authorize(Roles = RoleNames.Admin)]
|
||||
public void Delete(string siteId)
|
||||
{
|
||||
if (int.TryParse(siteId, out int parsedSiteId) && parsedSiteId == _alias.SiteId)
|
||||
{
|
||||
_logs.DeleteLogs(parsedSiteId, 0); // specifying zero for age results in all logs being deleted
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Security, "Unauthorized Log Delete Attempt {SiteId}", siteId);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using System.Net;
|
||||
using System.Security.Policy;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
|
@ -365,8 +365,8 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
{ "FrameworkVersion", moduleDefinition.Version },
|
||||
{ "ClientReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "ServerReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "SharedReference", $"<PackageReference Include=\"Oqtane.Client\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "ServerReference", $"<PackageReference Include=\"Oqtane.Server\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
{ "SharedReference", $"<PackageReference Include=\"Oqtane.Shared\" Version=\"{moduleDefinition.Version}\" />" },
|
||||
};
|
||||
});
|
||||
}
|
||||
|
41
Oqtane.Server/Controllers/SearchResultsController.cs
Normal file
41
Oqtane.Server/Controllers/SearchResultsController.cs
Normal file
@ -0,0 +1,41 @@
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Oqtane.Documentation;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
[Route(ControllerRoutes.ApiRoute)]
|
||||
public class SearchResultsController : ModuleControllerBase
|
||||
{
|
||||
private readonly ISearchService _searchService;
|
||||
|
||||
public SearchResultsController(ISearchService searchService, ILogManager logger, IHttpContextAccessor accessor) : base(logger, accessor)
|
||||
{
|
||||
_searchService = searchService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Authorize(Policy = PolicyNames.ViewModule)]
|
||||
public async Task<Models.SearchResults> Post([FromBody] Models.SearchQuery searchQuery)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await _searchService.SearchAsync(searchQuery);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Log(LogLevel.Error, this, LogFunction.Other, ex, "Fetch search results failed.", searchQuery);
|
||||
HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -81,5 +81,12 @@ namespace Oqtane.Controllers
|
||||
{
|
||||
await _siteService.DeleteSiteAsync(id);
|
||||
}
|
||||
|
||||
// GET api/<controller>/modules/5/6
|
||||
[HttpGet("modules/{siteId}/{pageId}")]
|
||||
public async Task<IEnumerable<Module>> GetModules(int siteId, int pageId)
|
||||
{
|
||||
return await _siteService.GetModulesAsync(siteId, pageId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,7 @@ namespace Oqtane.Controllers
|
||||
case "environment":
|
||||
systeminfo.Add("CLRVersion", Environment.Version.ToString());
|
||||
systeminfo.Add("OSVersion", Environment.OSVersion.ToString());
|
||||
systeminfo.Add("Process", (Environment.Is64BitProcess) ? "64 Bit" : "32 Bit");
|
||||
systeminfo.Add("MachineName", Environment.MachineName);
|
||||
systeminfo.Add("WorkingSet", Environment.WorkingSet.ToString());
|
||||
systeminfo.Add("TickCount", Environment.TickCount64.ToString());
|
||||
|
@ -8,6 +8,7 @@ using Oqtane.Infrastructure;
|
||||
using Oqtane.Repository;
|
||||
using System.Net;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Oqtane.Controllers
|
||||
{
|
||||
@ -33,7 +34,7 @@ namespace Oqtane.Controllers
|
||||
int SiteId;
|
||||
if (int.TryParse(siteid, out SiteId) && SiteId == _alias.SiteId)
|
||||
{
|
||||
return _visitors.GetVisitors(SiteId, DateTime.Parse(fromdate));
|
||||
return _visitors.GetVisitors(SiteId, DateTime.ParseExact(fromdate, "yyyy-MM-dd", CultureInfo.InvariantCulture));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Routing;
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.AspNetCore.Antiforgery;
|
||||
|
||||
namespace OqtaneSSR.Extensions
|
||||
{
|
||||
@ -23,6 +24,7 @@ namespace OqtaneSSR.Extensions
|
||||
{
|
||||
routeEndpointBuilder.Metadata.Add(new RootComponentMetadata(typeof(App)));
|
||||
routeEndpointBuilder.Metadata.Add(new ComponentTypeMetadata(typeof(App)));
|
||||
routeEndpointBuilder.Metadata.Add(new RequireAntiforgeryTokenAttribute());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,10 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.OpenApi.Models;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Infrastructure.Interfaces;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Managers;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Providers;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Services;
|
||||
@ -97,6 +99,10 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddScoped<IUrlMappingService, UrlMappingService>();
|
||||
services.AddScoped<IVisitorService, VisitorService>();
|
||||
services.AddScoped<ISyncService, SyncService>();
|
||||
services.AddScoped<ISearchResultsService, SearchResultsService>();
|
||||
services.AddScoped<ISearchService, SearchService>();
|
||||
services.AddScoped<ISearchProvider, DatabaseSearchProvider>();
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
@ -131,6 +137,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddTransient<ILanguageRepository, LanguageRepository>();
|
||||
services.AddTransient<IVisitorRepository, VisitorRepository>();
|
||||
services.AddTransient<IUrlMappingRepository, UrlMappingRepository>();
|
||||
services.AddTransient<ISearchContentRepository, SearchContentRepository>();
|
||||
|
||||
// managers
|
||||
services.AddTransient<IDBContextDependencies, DBContextDependencies>();
|
||||
@ -143,6 +150,9 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
services.AddTransient<IUpgradeManager, UpgradeManager>();
|
||||
services.AddTransient<IUserManager, UserManager>();
|
||||
|
||||
// providers
|
||||
services.AddTransient<ITextEditorProvider, QuillTextEditorProvider>();
|
||||
|
||||
// obsolete - replaced by ITenantManager
|
||||
services.AddTransient<ITenantResolver, TenantResolver>();
|
||||
|
||||
|
@ -539,6 +539,8 @@ namespace Oqtane.Infrastructure
|
||||
var identityUserManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
|
||||
|
||||
var tenant = tenants.GetTenants().FirstOrDefault(item => item.Name == install.TenantName);
|
||||
var rendermode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value;
|
||||
var runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value;
|
||||
|
||||
site = new Site
|
||||
{
|
||||
@ -556,9 +558,9 @@ namespace Oqtane.Infrastructure
|
||||
DefaultContainerType = (!string.IsNullOrEmpty(install.DefaultContainer)) ? install.DefaultContainer : Constants.DefaultContainer,
|
||||
AdminContainerType = (!string.IsNullOrEmpty(install.DefaultAdminContainer)) ? install.DefaultAdminContainer : Constants.DefaultAdminContainer,
|
||||
SiteTemplateType = install.SiteTemplate,
|
||||
RenderMode = (!string.IsNullOrEmpty(install.RenderMode)) ? install.RenderMode : _configManager.GetSection("RenderMode").Value,
|
||||
Runtime = (!string.IsNullOrEmpty(install.Runtime)) ? install.Runtime : _configManager.GetSection("Runtime").Value,
|
||||
Prerender = true,
|
||||
RenderMode = rendermode,
|
||||
Runtime = runtime,
|
||||
Prerender = (rendermode == RenderModes.Interactive),
|
||||
Hybrid = false
|
||||
};
|
||||
site = sites.AddSite(site);
|
||||
|
@ -19,12 +19,8 @@ namespace Oqtane.Infrastructure.EventSubscribers
|
||||
// when site entities change (ie. site, pages, modules, etc...) a site refresh event is raised and the site cache item needs to be refreshed
|
||||
if (syncEvent.EntityName == EntityNames.Site && syncEvent.Action == SyncEventActions.Refresh)
|
||||
{
|
||||
_cache.Remove($"site:{syncEvent.TenantId}:{syncEvent.EntityId}*", true);
|
||||
}
|
||||
// when user is modified (ie. roles) a a site reload event is raised and the site cache item for the user needs to be refreshed
|
||||
if (syncEvent.EntityName == EntityNames.User && syncEvent.Action == SyncEventActions.Reload)
|
||||
{
|
||||
_cache.Remove($"site:{syncEvent.TenantId}:{syncEvent.SiteId}:{syncEvent.EntityId}", true);
|
||||
_cache.Remove($"site:{syncEvent.TenantId}:{syncEvent.EntityId}");
|
||||
_cache.Remove($"modules:{syncEvent.TenantId}:{syncEvent.EntityId}");
|
||||
}
|
||||
|
||||
// when a site entity is updated, the hosting model may have changed so the client assemblies cache items need to be refreshed
|
||||
|
@ -197,6 +197,12 @@ namespace Oqtane.Infrastructure
|
||||
string[] segments = entry.FullName.Split('/'); // ZipArchiveEntries always use unix path separator
|
||||
string filename = Path.Combine(folder, string.Join(Path.DirectorySeparatorChar, segments, ignoreLeadingSegments, segments.Length - ignoreLeadingSegments));
|
||||
|
||||
// validate path to prevent path traversal
|
||||
if (!Path.GetFullPath(filename).StartsWith(folder + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (!Directory.Exists(Path.GetDirectoryName(filename)))
|
||||
@ -227,6 +233,7 @@ namespace Oqtane.Infrastructure
|
||||
// an error occurred extracting the file
|
||||
filename = "";
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
|
90
Oqtane.Server/Infrastructure/Jobs/SearchIndexJob.cs
Normal file
90
Oqtane.Server/Infrastructure/Jobs/SearchIndexJob.cs
Normal file
@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Infrastructure
|
||||
{
|
||||
public class SearchIndexJob : HostedServiceBase
|
||||
{
|
||||
private const string SearchIndexStartTimeSettingName = "SearchIndex_StartTime";
|
||||
|
||||
public SearchIndexJob(IServiceScopeFactory serviceScopeFactory) : base(serviceScopeFactory)
|
||||
{
|
||||
Name = "Search Index Job";
|
||||
Frequency = "m"; // run every minute.
|
||||
Interval = 1;
|
||||
IsEnabled = true;
|
||||
}
|
||||
|
||||
public override string ExecuteJob(IServiceProvider provider)
|
||||
{
|
||||
// get services
|
||||
var siteRepository = provider.GetRequiredService<ISiteRepository>();
|
||||
var settingRepository = provider.GetRequiredService<ISettingRepository>();
|
||||
var logRepository = provider.GetRequiredService<ILogRepository>();
|
||||
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 />");
|
||||
var currentTime = DateTime.UtcNow;
|
||||
|
||||
searchService.IndexContent(site.SiteId, startTime, logNote =>
|
||||
{
|
||||
logs.AppendLine(logNote);
|
||||
}, handleError =>
|
||||
{
|
||||
logs.AppendLine(handleError);
|
||||
});
|
||||
|
||||
UpdateSearchStartTime(site.SiteId, currentTime, settingRepository);
|
||||
|
||||
logs.AppendLine($"Search: End index site: {site.Name}<br />");
|
||||
}
|
||||
|
||||
return logs.ToString();
|
||||
}
|
||||
|
||||
private DateTime? GetSearchStartTime(int siteId, ISettingRepository settingRepository)
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchIndexStartTimeSettingName);
|
||||
if(setting == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Convert.ToDateTime(setting.SettingValue);
|
||||
}
|
||||
|
||||
private void UpdateSearchStartTime(int siteId, DateTime startTime, ISettingRepository settingRepository)
|
||||
{
|
||||
var setting = settingRepository.GetSetting(EntityNames.Site, siteId, SearchIndexStartTimeSettingName);
|
||||
if (setting == null)
|
||||
{
|
||||
setting = new Setting
|
||||
{
|
||||
EntityName = EntityNames.Site,
|
||||
EntityId = siteId,
|
||||
SettingName = SearchIndexStartTimeSettingName,
|
||||
SettingValue = Convert.ToString(startTime),
|
||||
};
|
||||
|
||||
settingRepository.AddSetting(setting);
|
||||
}
|
||||
else
|
||||
{
|
||||
setting.SettingValue = Convert.ToString(startTime);
|
||||
settingRepository.UpdateSetting(setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -203,19 +203,21 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
if (Enum.Parse<LogLevel>(log.Level) >= notifylevel)
|
||||
{
|
||||
var subject = $"Site {log.Level} Notification";
|
||||
string body = $"Log Message: {log.Message}";
|
||||
|
||||
var alias = _tenantManager.GetAlias();
|
||||
foreach (var userrole in _userRoles.GetUserRoles(log.SiteId.Value))
|
||||
if (alias != null)
|
||||
{
|
||||
if (userrole.Role.Name == RoleNames.Host)
|
||||
{
|
||||
var subject = $"{alias.Name} Site {log.Level} Notification";
|
||||
var url = $"{_accessor.HttpContext.Request.Scheme}://{alias.Name}/admin/log?id={log.LogId}";
|
||||
string body = $"Log Message: {log.Message}<br /><br />Please visit {url} for more information";
|
||||
var notification = new Notification(log.SiteId.Value, userrole.User, subject, body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
subject = $"{alias.Name} Site {log.Level} Notification";
|
||||
body = $"Log Message: {log.Message}<br /><br />Please visit {alias.Protocol}://{alias.Name}/admin/log?id={log.LogId} for more information";
|
||||
}
|
||||
|
||||
foreach (var userrole in _userRoles.GetUserRoles(RoleNames.Host, log.SiteId.Value))
|
||||
{
|
||||
var notification = new Notification(log.SiteId.Value, userrole.User, subject, body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
745
Oqtane.Server/Infrastructure/SiteTemplates/AdminSiteTemplate.cs
Normal file
745
Oqtane.Server/Infrastructure/SiteTemplates/AdminSiteTemplate.cs
Normal file
@ -0,0 +1,745 @@
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Infrastructure;
|
||||
using System.Collections.Generic;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Documentation;
|
||||
|
||||
namespace Oqtane.SiteTemplates
|
||||
{
|
||||
[PrivateApi("Mark Site-Template classes as private, since it's not very useful in the public docs")]
|
||||
public class AdminSiteTemplate : ISiteTemplate
|
||||
{
|
||||
public string Name
|
||||
{
|
||||
get { return "Admin Site Template"; }
|
||||
}
|
||||
|
||||
public List<PageTemplate> CreateSite(Site site)
|
||||
{
|
||||
var pageTemplates = new List<PageTemplate>();
|
||||
var seed = 1000; // order
|
||||
|
||||
// user pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Login",
|
||||
Parent = "",
|
||||
Path = "login",
|
||||
Order = seed + 1,
|
||||
Icon = Icons.LockLocked,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Register",
|
||||
Parent = "",
|
||||
Path = "register",
|
||||
Order = seed + 3,
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Reset",
|
||||
Parent = "",
|
||||
Path = "reset",
|
||||
Order = seed + 5,
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Profile",
|
||||
Parent = "",
|
||||
Path = "profile",
|
||||
Order = seed + 7,
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Search",
|
||||
Parent = "",
|
||||
Path = "search",
|
||||
Order = seed + 9,
|
||||
Icon = "oi oi-magnifying-glass",
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule> {
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.SearchResults, Oqtane.Client", Title = "Search", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Not Found",
|
||||
Parent = "",
|
||||
Path = "404",
|
||||
Order = seed + 11,
|
||||
Icon = Icons.X,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Not Found", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = "<p>The page you requested does not exist or you do not have sufficient rights to view it.</p>"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// admin pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Admin",
|
||||
Parent = "",
|
||||
Path = "admin",
|
||||
Order = seed + 51,
|
||||
Icon = "",
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Site Settings",
|
||||
Parent = "Admin",
|
||||
Order = 1,
|
||||
Path = "admin/site",
|
||||
Icon = Icons.Home,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Page Management",
|
||||
Parent = "Admin",
|
||||
Order = 3,
|
||||
Path = "admin/pages",
|
||||
Icon = Icons.Layers,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "User Management",
|
||||
Parent = "Admin",
|
||||
Order = 5,
|
||||
Path = "admin/users",
|
||||
Icon = Icons.People,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Profile Management",
|
||||
Parent = "Admin",
|
||||
Order = 7,
|
||||
Path = "admin/profiles",
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Role Management",
|
||||
Parent = "Admin",
|
||||
Order = 9,
|
||||
Path = "admin/roles",
|
||||
Icon = Icons.LockLocked,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "File Management",
|
||||
Parent = "Admin",
|
||||
Order = 11,
|
||||
Path = "admin/files",
|
||||
Icon = Icons.File,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Recycle Bin",
|
||||
Parent = "Admin",
|
||||
Order = 13,
|
||||
Path = "admin/recyclebin",
|
||||
Icon = Icons.Trash,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Url Mappings",
|
||||
Parent = "Admin",
|
||||
Order = 15,
|
||||
Path = "admin/urlmappings",
|
||||
Icon = Icons.LinkBroken,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UrlMappings.Index).ToModuleDefinitionName(), Title = "Url Mappings", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Visitor Management",
|
||||
Parent = "Admin",
|
||||
Order = 17,
|
||||
Path = "admin/visitors",
|
||||
Icon = Icons.Eye,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Visitors.Index).ToModuleDefinitionName(), Title = "Visitor Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// host pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Event Log",
|
||||
Parent = "Admin",
|
||||
Order = 19,
|
||||
Path = "admin/log",
|
||||
Icon = Icons.MagnifyingGlass,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Site Management",
|
||||
Parent = "Admin",
|
||||
Order = 21,
|
||||
Path = "admin/sites",
|
||||
Icon = Icons.Globe,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Module Management",
|
||||
Parent = "Admin",
|
||||
Order = 23,
|
||||
Path = "admin/modules",
|
||||
Icon = Icons.Browser,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Theme Management",
|
||||
Parent = "Admin",
|
||||
Order = 25,
|
||||
Path = "admin/themes",
|
||||
Icon = Icons.Brush,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Language Management",
|
||||
Parent = "Admin",
|
||||
Order = 27,
|
||||
Path = "admin/languages",
|
||||
Icon = Icons.Text,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Scheduled Jobs",
|
||||
Parent = "Admin",
|
||||
Order = 29,
|
||||
Path = "admin/jobs",
|
||||
Icon = Icons.Timer,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Sql Management",
|
||||
Parent = "Admin",
|
||||
Order = 31,
|
||||
Path = "admin/sql",
|
||||
Icon = Icons.Spreadsheet,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "System Info",
|
||||
Parent = "Admin",
|
||||
Order = 33,
|
||||
Path = "admin/system",
|
||||
Icon = Icons.MedicalCross,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "System Update",
|
||||
Parent = "Admin",
|
||||
Order = 35,
|
||||
Path = "admin/update",
|
||||
Icon = Icons.Aperture,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return pageTemplates;
|
||||
}
|
||||
}
|
||||
}
|
@ -93,6 +93,7 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
|
||||
var result = new StringBuilder();
|
||||
source = source.Replace("[[", "[$_["); //avoid nested square bracket issue.
|
||||
foreach (Match match in this.TokenizerRegex.Matches(source))
|
||||
{
|
||||
var key = match.Result("${key}");
|
||||
@ -126,7 +127,7 @@ namespace Oqtane.Infrastructure
|
||||
result.Append(match.Result("${text}"));
|
||||
}
|
||||
}
|
||||
|
||||
result.Replace("[$_", "["); //restore the changes.
|
||||
return result.ToString();
|
||||
}
|
||||
|
||||
|
@ -66,6 +66,9 @@ namespace Oqtane.Infrastructure
|
||||
case "5.1.0":
|
||||
Upgrade_5_1_0(tenant, scope);
|
||||
break;
|
||||
case "5.2.0":
|
||||
Upgrade_5_2_0(tenant, scope);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -385,5 +388,48 @@ namespace Oqtane.Infrastructure
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void Upgrade_5_2_0(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
CreateSearchResultsPages(tenant, scope);
|
||||
}
|
||||
|
||||
private void CreateSearchResultsPages(Tenant tenant, IServiceScope scope)
|
||||
{
|
||||
var pageTemplates = new List<PageTemplate>();
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Search",
|
||||
Parent = "",
|
||||
Path = "search",
|
||||
Icon = "oi oi-magnifying-glass",
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule> {
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.SearchResults, Oqtane.Client", Title = "Search", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var pages = scope.ServiceProvider.GetRequiredService<IPageRepository>();
|
||||
var sites = scope.ServiceProvider.GetRequiredService<ISiteRepository>();
|
||||
foreach (var site in sites.GetSites().ToList())
|
||||
{
|
||||
if (!pages.GetPages(site.SiteId).ToList().Where(item => item.Path == "search").Any())
|
||||
{
|
||||
sites.CreatePages(site, pageTemplates, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
145
Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs
Normal file
145
Oqtane.Server/Managers/Search/ModuleSearchIndexManager.cs
Normal file
@ -0,0 +1,145 @@
|
||||
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() });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
60
Oqtane.Server/Managers/Search/ModuleSearchResultManager.cs
Normal file
60
Oqtane.Server/Managers/Search/ModuleSearchResultManager.cs
Normal file
@ -0,0 +1,60 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Managers.Search
|
||||
{
|
||||
public class ModuleSearchResultManager : ISearchResultManager
|
||||
{
|
||||
public string Name => EntityNames.Module;
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
|
||||
public ModuleSearchResultManager(
|
||||
IServiceProvider serviceProvider)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public string GetUrl(SearchResult searchResult, SearchQuery searchQuery)
|
||||
{
|
||||
var pageRepository = _serviceProvider.GetRequiredService<IPageRepository>();
|
||||
var pageIdValue = searchResult.SearchContentProperties?.FirstOrDefault(i => i.Name == Constants.SearchPageIdPropertyName)?.Value ?? string.Empty;
|
||||
if(!string.IsNullOrEmpty(pageIdValue) && int.TryParse(pageIdValue, out int pageId))
|
||||
{
|
||||
var page = pageRepository.GetPage(pageId);
|
||||
if (page != null)
|
||||
{
|
||||
return $"{searchQuery.Alias.Protocol}{searchQuery.Alias.Name}{(!string.IsNullOrEmpty(page.Path) && !page.Path.StartsWith("/") ? "/" : "")}{page.Path}";
|
||||
}
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public bool Visible(SearchContent searchResult, SearchQuery searchQuery)
|
||||
{
|
||||
var pageIdValue = searchResult.SearchContentProperties?.FirstOrDefault(i => i.Name == Constants.SearchPageIdPropertyName)?.Value ?? string.Empty;
|
||||
if (!string.IsNullOrEmpty(pageIdValue) && int.TryParse(pageIdValue, out int pageId))
|
||||
{
|
||||
return CanViewPage(pageId, searchQuery.User);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CanViewPage(int pageId, User user)
|
||||
{
|
||||
var pageRepository = _serviceProvider.GetRequiredService<IPageRepository>();
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
89
Oqtane.Server/Managers/Search/PageSearchIndexManager.cs
Normal file
89
Oqtane.Server/Managers/Search/PageSearchIndexManager.cs
Normal file
@ -0,0 +1,89 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
36
Oqtane.Server/Managers/Search/SearchIndexManagerBase.cs
Normal file
36
Oqtane.Server/Managers/Search/SearchIndexManagerBase.cs
Normal file
@ -0,0 +1,36 @@
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
@ -201,56 +201,54 @@ namespace Oqtane.Managers
|
||||
IdentityUser identityuser = await _identityUserManager.FindByNameAsync(user.Username);
|
||||
if (identityuser != null)
|
||||
{
|
||||
var valid = true;
|
||||
if (!string.IsNullOrEmpty(user.Password))
|
||||
{
|
||||
var validator = new PasswordValidator<IdentityUser>();
|
||||
var result = await validator.ValidateAsync(_identityUserManager, null, user.Password);
|
||||
valid = result.Succeeded;
|
||||
if (valid)
|
||||
if (result.Succeeded)
|
||||
{
|
||||
identityuser.PasswordHash = _identityUserManager.PasswordHasher.HashPassword(identityuser, user.Password);
|
||||
await _identityUserManager.UpdateAsync(identityuser);
|
||||
}
|
||||
}
|
||||
if (valid)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(user.Password))
|
||||
else
|
||||
{
|
||||
await _identityUserManager.UpdateAsync(identityuser); // requires password to be provided
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. Password Does Not Meet Complexity Requirements.", user.Username);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (user.Email != identityuser.Email)
|
||||
{
|
||||
await _identityUserManager.SetEmailAsync(identityuser, user.Email);
|
||||
|
||||
// if email address changed and user is not administrator, email verification is required for new email address
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
var alias = _tenantManager.GetAlias();
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
else
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
}
|
||||
}
|
||||
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
|
||||
if (user.Email != identityuser.Email)
|
||||
{
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. Password Does Not Meet Complexity Requirements.", user.Username);
|
||||
user = null;
|
||||
await _identityUserManager.SetEmailAsync(identityuser, user.Email);
|
||||
|
||||
// if email address changed and it is not confirmed, verification is required for new email address
|
||||
if (!user.EmailConfirmed)
|
||||
{
|
||||
var alias = _tenantManager.GetAlias();
|
||||
string token = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
string url = alias.Protocol + alias.Name + "/login?name=" + user.Username + "&token=" + WebUtility.UrlEncode(token);
|
||||
string body = "Dear " + user.DisplayName + ",\n\nIn Order To Verify The Email Address Associated To Your User Account Please Click The Link Displayed Below:\n\n" + url + "\n\nThank You!";
|
||||
var notification = new Notification(user.SiteId, user, "User Account Verification", body);
|
||||
_notifications.AddNotification(notification);
|
||||
}
|
||||
}
|
||||
|
||||
if (user.EmailConfirmed)
|
||||
{
|
||||
var emailConfirmationToken = await _identityUserManager.GenerateEmailConfirmationTokenAsync(identityuser);
|
||||
await _identityUserManager.ConfirmEmailAsync(identityuser, emailConfirmationToken);
|
||||
}
|
||||
|
||||
user = _users.UpdateUser(user);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Update);
|
||||
_syncManager.AddSyncEvent(_tenantManager.GetAlias(), EntityNames.User, user.UserId, SyncEventActions.Reload);
|
||||
user.Password = ""; // remove sensitive information
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Update, "User Updated {User}", user);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Log(user.SiteId, LogLevel.Error, this, LogFunction.Update, "Unable To Update User {Username}. User Does Not Exist.", user.Username);
|
||||
user = null;
|
||||
}
|
||||
|
||||
return user;
|
||||
|
@ -0,0 +1,64 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public class SearchContentEntityBuilder : BaseEntityBuilder<SearchContentEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "SearchContent";
|
||||
private readonly PrimaryKey<SearchContentEntityBuilder> _primaryKey = new("PK_SearchContent", x => x.SearchContentId);
|
||||
|
||||
public SearchContentEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
}
|
||||
|
||||
protected override SearchContentEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
SearchContentId = AddAutoIncrementColumn(table, "SearchContentId");
|
||||
SiteId = AddIntegerColumn(table, "SiteId");
|
||||
EntityName = AddStringColumn(table, "EntityName", 50);
|
||||
EntityId = AddStringColumn(table, "EntityId", 50);
|
||||
Title = AddStringColumn(table, "Title", 200);
|
||||
Description = AddMaxStringColumn(table, "Description");
|
||||
Body = AddMaxStringColumn(table, "Body");
|
||||
Url = AddStringColumn(table, "Url", 500);
|
||||
Permissions = AddStringColumn(table, "Permissions", 100);
|
||||
ContentModifiedBy = AddStringColumn(table, "ContentModifiedBy", 256);
|
||||
ContentModifiedOn = AddDateTimeColumn(table, "ContentModifiedOn");
|
||||
AdditionalContent = AddMaxStringColumn(table, "AdditionalContent");
|
||||
CreatedOn = AddDateTimeColumn(table, "CreatedOn");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchContentId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SiteId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> EntityName { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> EntityId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Title { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Description { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Body { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Url { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Permissions { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> ContentModifiedBy { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> ContentModifiedOn { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> AdditionalContent { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> CreatedOn { get; private set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public class SearchContentPropertyEntityBuilder : BaseEntityBuilder<SearchContentPropertyEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "SearchContentProperty";
|
||||
private readonly PrimaryKey<SearchContentPropertyEntityBuilder> _primaryKey = new("PK_SearchContentProperty", x => x.PropertyId);
|
||||
private readonly ForeignKey<SearchContentPropertyEntityBuilder> _searchContentForeignKey = new("FK_SearchContentProperty_SearchContent", x => x.SearchContentId, "SearchContent", "SearchContentId", ReferentialAction.Cascade);
|
||||
|
||||
public SearchContentPropertyEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
|
||||
ForeignKeys.Add(_searchContentForeignKey);
|
||||
}
|
||||
|
||||
protected override SearchContentPropertyEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
PropertyId = AddAutoIncrementColumn(table, "PropertyId");
|
||||
SearchContentId = AddIntegerColumn(table, "SearchContentId");
|
||||
Name = AddStringColumn(table, "Name", 50);
|
||||
Value = AddStringColumn(table, "Value", 50);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> PropertyId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchContentId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Name { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Value { get; private set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public class SearchContentWordEntityBuilder : BaseEntityBuilder<SearchContentWordEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "SearchContentWord";
|
||||
private readonly PrimaryKey<SearchContentWordEntityBuilder> _primaryKey = new("PK_SearchContentWord", x => x.SearchContentWordId);
|
||||
private readonly ForeignKey<SearchContentWordEntityBuilder> _foreignKey1 = new("FK_SearchContentWord_SearchContent", x => x.SearchContentId, "SearchContent", "SearchContentId", ReferentialAction.Cascade);
|
||||
private readonly ForeignKey<SearchContentWordEntityBuilder> _foreignKey2 = new("FK_SearchContentWord_SearchWord", x => x.SearchWordId, "SearchWord", "SearchWordId", ReferentialAction.Cascade);
|
||||
|
||||
public SearchContentWordEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
ForeignKeys.Add(_foreignKey1);
|
||||
ForeignKeys.Add(_foreignKey2);
|
||||
}
|
||||
|
||||
protected override SearchContentWordEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
SearchContentWordId = AddAutoIncrementColumn(table, "SearchContentWordId");
|
||||
SearchContentId = AddIntegerColumn(table, "SearchContentId");
|
||||
SearchWordId = AddIntegerColumn(table, "SearchWordId");
|
||||
Count = AddIntegerColumn(table, "Count");
|
||||
CreatedOn = AddDateTimeColumn(table, "CreatedOn");
|
||||
ModifiedOn = AddDateTimeColumn(table, "ModifiedOn");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchContentWordId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchContentId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchWordId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Count { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> CreatedOn { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> ModifiedOn { get; private set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations;
|
||||
using Microsoft.EntityFrameworkCore.Migrations.Operations.Builders;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
|
||||
namespace Oqtane.Migrations.EntityBuilders
|
||||
{
|
||||
public class SearchWordEntityBuilder : BaseEntityBuilder<SearchWordEntityBuilder>
|
||||
{
|
||||
private const string _entityTableName = "SearchWord";
|
||||
private readonly PrimaryKey<SearchWordEntityBuilder> _primaryKey = new("PK_SearchWord", x => x.SearchWordId);
|
||||
|
||||
public SearchWordEntityBuilder(MigrationBuilder migrationBuilder, IDatabase database) : base(migrationBuilder, database)
|
||||
{
|
||||
EntityTableName = _entityTableName;
|
||||
PrimaryKey = _primaryKey;
|
||||
}
|
||||
|
||||
protected override SearchWordEntityBuilder BuildTable(ColumnsBuilder table)
|
||||
{
|
||||
SearchWordId = AddAutoIncrementColumn(table, "SearchWordId");
|
||||
Word = AddStringColumn(table, "Word", 255);
|
||||
CreatedOn = AddDateTimeColumn(table, "CreatedOn");
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public OperationBuilder<AddColumnOperation> SearchWordId { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> Word { get; private set; }
|
||||
|
||||
public OperationBuilder<AddColumnOperation> CreatedOn { get; private set; }
|
||||
}
|
||||
}
|
50
Oqtane.Server/Migrations/Tenant/05020001_AddSearchTables.cs
Normal file
50
Oqtane.Server/Migrations/Tenant/05020001_AddSearchTables.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Oqtane.Databases.Interfaces;
|
||||
using Oqtane.Migrations.EntityBuilders;
|
||||
using Oqtane.Repository;
|
||||
|
||||
namespace Oqtane.Migrations.Tenant
|
||||
{
|
||||
[DbContext(typeof(TenantDBContext))]
|
||||
[Migration("Tenant.05.02.00.01")]
|
||||
public class AddSearchTables : MultiDatabaseMigration
|
||||
{
|
||||
public AddSearchTables(IDatabase database) : base(database)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var searchContentEntityBuilder = new SearchContentEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentEntityBuilder.Create();
|
||||
|
||||
var searchContentPropertyEntityBuilder = new SearchContentPropertyEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentPropertyEntityBuilder.Create();
|
||||
|
||||
var searchWordEntityBuilder = new SearchWordEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchWordEntityBuilder.Create();
|
||||
searchWordEntityBuilder.AddIndex("IX_SearchWord", "Word", true);
|
||||
|
||||
var searchContentWordEntityBuilder = new SearchContentWordEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentWordEntityBuilder.Create();
|
||||
}
|
||||
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
var searchContentWordEntityBuilder = new SearchContentWordEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentWordEntityBuilder.Drop();
|
||||
|
||||
var searchWordEntityBuilder = new SearchWordEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchWordEntityBuilder.DropIndex("IX_SearchWord");
|
||||
searchWordEntityBuilder.Drop();
|
||||
|
||||
var searchContentPropertyEntityBuilder = new SearchContentPropertyEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentPropertyEntityBuilder.Drop();
|
||||
|
||||
var searchContentEntityBuilder = new SearchContentEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||
searchContentEntityBuilder.Drop();
|
||||
}
|
||||
}
|
||||
}
|
@ -7,20 +7,30 @@ using Oqtane.Repository;
|
||||
using Oqtane.Shared;
|
||||
using Oqtane.Migrations.Framework;
|
||||
using Oqtane.Documentation;
|
||||
using System.Linq;
|
||||
using Oqtane.Interfaces;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
|
||||
// ReSharper disable ConvertToUsingDeclaration
|
||||
|
||||
namespace Oqtane.Modules.HtmlText.Manager
|
||||
{
|
||||
[PrivateApi("Mark HtmlText classes as private, since it's not very useful in the public docs")]
|
||||
public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable
|
||||
public class HtmlTextManager : MigratableModuleBase, IInstallable, IPortable, ISearchable
|
||||
{
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly IHtmlTextRepository _htmlText;
|
||||
private readonly IDBContextDependencies _DBContextDependencies;
|
||||
private readonly ISqlRepository _sqlRepository;
|
||||
|
||||
public HtmlTextManager(IHtmlTextRepository htmlText, IDBContextDependencies DBContextDependencies, ISqlRepository sqlRepository)
|
||||
public HtmlTextManager(
|
||||
IServiceProvider serviceProvider,
|
||||
IHtmlTextRepository htmlText,
|
||||
IDBContextDependencies DBContextDependencies,
|
||||
ISqlRepository sqlRepository)
|
||||
{
|
||||
_serviceProvider = serviceProvider;
|
||||
_htmlText = htmlText;
|
||||
_DBContextDependencies = DBContextDependencies;
|
||||
_sqlRepository = sqlRepository;
|
||||
@ -29,14 +39,37 @@ namespace Oqtane.Modules.HtmlText.Manager
|
||||
public string ExportModule(Module module)
|
||||
{
|
||||
string content = "";
|
||||
var htmlText = _htmlText.GetHtmlText(module.ModuleId);
|
||||
if (htmlText != null)
|
||||
var htmltexts = _htmlText.GetHtmlTexts(module.ModuleId);
|
||||
if (htmltexts != null && htmltexts.Any())
|
||||
{
|
||||
content = WebUtility.HtmlEncode(htmlText.Content);
|
||||
var htmltext = htmltexts.OrderByDescending(item => item.CreatedOn).First();
|
||||
content = WebUtility.HtmlEncode(htmltext.Content);
|
||||
}
|
||||
return content;
|
||||
}
|
||||
|
||||
public List<SearchContent> GetSearchContents(PageModule pageModule, DateTime startDate)
|
||||
{
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
var htmltexts = _htmlText.GetHtmlTexts(pageModule.ModuleId);
|
||||
if (htmltexts != null && htmltexts.Any(i => i.CreatedOn >= startDate))
|
||||
{
|
||||
var htmltext = htmltexts.OrderByDescending(item => item.CreatedOn).First();
|
||||
|
||||
searchContentList.Add(new SearchContent
|
||||
{
|
||||
Title = pageModule.Module.Title,
|
||||
Description = string.Empty,
|
||||
Body = htmltext.Content,
|
||||
ContentModifiedBy = htmltext.ModifiedBy,
|
||||
ContentModifiedOn = htmltext.ModifiedOn
|
||||
});
|
||||
}
|
||||
|
||||
return searchContentList;
|
||||
}
|
||||
|
||||
public void ImportModule(Module module, string content, string version)
|
||||
{
|
||||
content = WebUtility.HtmlDecode(content);
|
||||
|
@ -3,7 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>5.1.0</Version>
|
||||
<Version>5.2.0</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
@ -11,7 +11,7 @@
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.1.0</PackageReleaseNotes>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v5.2.0</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
@ -33,19 +33,20 @@
|
||||
<EmbeddedResource Include="Scripts\MigrateTenant.sql" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.61" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.6">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.6" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.4" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Data.Sqlite.Core" Version="8.0.6" />
|
||||
<PackageReference Include="SQLitePCLRaw.bundle_e_sqlite3" Version="2.1.8" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -46,15 +46,27 @@ 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) && page.IsNavigation)
|
||||
if (_userPermissions.IsAuthorized(null, PermissionNames.View, page.PermissionList) && !internalPaths.Contains(page.Path))
|
||||
{
|
||||
var rooturl = _alias.Protocol + (string.IsNullOrEmpty(_alias.Path) ? _alias.Name : _alias.Name.Substring(0, _alias.Name.IndexOf("/")));
|
||||
sitemap.Add(new Sitemap { Url = rooturl + Utilities.NavigateUrl(_alias.Path, page.Path, ""), ModifiedOn = DateTime.UtcNow });
|
||||
var pageurl = rooturl;
|
||||
if (string.IsNullOrEmpty(page.Url))
|
||||
{
|
||||
pageurl += Utilities.NavigateUrl(_alias.Path, page.Path, "");
|
||||
}
|
||||
else
|
||||
{
|
||||
pageurl += (page.Url.StartsWith("/") ? "" : "/") + page.Url;
|
||||
}
|
||||
sitemap.Add(new Sitemap { Url = pageurl, ModifiedOn = DateTime.UtcNow });
|
||||
|
||||
foreach (var pageModule in pageModules.Where(item => item.PageId == page.PageId))
|
||||
{
|
||||
|
311
Oqtane.Server/Providers/DatabaseSearchProvider.cs
Normal file
311
Oqtane.Server/Providers/DatabaseSearchProvider.cs
Normal file
@ -0,0 +1,311 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using HtmlAgilityPack;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Services;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Providers
|
||||
{
|
||||
public class DatabaseSearchProvider : ISearchProvider
|
||||
{
|
||||
private readonly ISearchContentRepository _searchContentRepository;
|
||||
|
||||
private const string IgnoreWords = "the,be,to,of,and,a,i,in,that,have,it,for,not,on,with,he,as,you,do,at,this,but,his,by,from,they,we,say,her,she,or,an,will,my,one,all,would,there,their,what,so,up,out,if,about,who,get,which,go,me,when,make,can,like,time,no,just,him,know,take,people,into,year,your,good,some,could,them,see,other,than,then,now,look,only,come,its,over,think,also,back,after,use,two,how,our,work,first,well,way,even,new,want,because,any,these,give,day,most,us";
|
||||
private const int WordMinLength = 3;
|
||||
public string Name => Constants.DefaultSearchProviderName;
|
||||
|
||||
public DatabaseSearchProvider(ISearchContentRepository searchContentRepository)
|
||||
{
|
||||
_searchContentRepository = searchContentRepository;
|
||||
}
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
}
|
||||
|
||||
public void DeleteSearchContent(string id)
|
||||
{
|
||||
_searchContentRepository.DeleteSearchContent(id);
|
||||
}
|
||||
|
||||
public bool Optimize()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ResetIndex()
|
||||
{
|
||||
_searchContentRepository.DeleteAllSearchContent();
|
||||
}
|
||||
|
||||
public void SaveSearchContent(SearchContent searchContent, bool autoCommit = false)
|
||||
{
|
||||
//remove exist document
|
||||
_searchContentRepository.DeleteSearchContent(searchContent.EntityName, searchContent.EntityId);
|
||||
|
||||
//clean the search content to remove html tags
|
||||
CleanSearchContent(searchContent);
|
||||
|
||||
_searchContentRepository.AddSearchContent(searchContent);
|
||||
|
||||
//save the index words
|
||||
AnalyzeSearchContent(searchContent);
|
||||
}
|
||||
|
||||
public async Task<SearchResults> SearchAsync(SearchQuery searchQuery, Func<SearchContent, SearchQuery, bool> validateFunc)
|
||||
{
|
||||
var totalResults = 0;
|
||||
|
||||
var searchContentList = await _searchContentRepository.GetSearchContentsAsync(searchQuery);
|
||||
|
||||
//convert the search content to search results.
|
||||
var results = searchContentList
|
||||
.Where(i => validateFunc(i, searchQuery))
|
||||
.Select(i => ConvertToSearchResult(i, searchQuery));
|
||||
|
||||
if (searchQuery.SortDirection == SearchSortDirections.Descending)
|
||||
{
|
||||
switch (searchQuery.SortField)
|
||||
{
|
||||
case SearchSortFields.Relevance:
|
||||
results = results.OrderByDescending(i => i.Score).ThenByDescending(i => i.ContentModifiedOn);
|
||||
break;
|
||||
case SearchSortFields.Title:
|
||||
results = results.OrderByDescending(i => i.Title).ThenByDescending(i => i.ContentModifiedOn);
|
||||
break;
|
||||
default:
|
||||
results = results.OrderByDescending(i => i.ContentModifiedOn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (searchQuery.SortField)
|
||||
{
|
||||
case SearchSortFields.Relevance:
|
||||
results = results.OrderBy(i => i.Score).ThenByDescending(i => i.ContentModifiedOn);
|
||||
break;
|
||||
case SearchSortFields.Title:
|
||||
results = results.OrderBy(i => i.Title).ThenByDescending(i => i.ContentModifiedOn);
|
||||
break;
|
||||
default:
|
||||
results = results.OrderBy(i => i.ContentModifiedOn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//remove duplicated results based on page id for Page and Module types
|
||||
results = results.DistinctBy(i =>
|
||||
{
|
||||
if (i.EntityName == EntityNames.Page || i.EntityName == EntityNames.Module)
|
||||
{
|
||||
var pageId = i.SearchContentProperties.FirstOrDefault(p => p.Name == Constants.SearchPageIdPropertyName)?.Value ?? string.Empty;
|
||||
return !string.IsNullOrEmpty(pageId) ? pageId : i.UniqueKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
return i.UniqueKey;
|
||||
}
|
||||
});
|
||||
|
||||
totalResults = results.Count();
|
||||
|
||||
return new SearchResults
|
||||
{
|
||||
Results = results.Skip(searchQuery.PageIndex * searchQuery.PageSize).Take(searchQuery.PageSize).ToList(),
|
||||
TotalResults = totalResults
|
||||
};
|
||||
}
|
||||
|
||||
private SearchResult ConvertToSearchResult(SearchContent searchContent, SearchQuery searchQuery)
|
||||
{
|
||||
var searchResult = new SearchResult()
|
||||
{
|
||||
SearchContentId = searchContent.SearchContentId,
|
||||
SiteId = searchContent.SiteId,
|
||||
EntityName = searchContent.EntityName,
|
||||
EntityId = searchContent.EntityId,
|
||||
Title = searchContent.Title,
|
||||
Description = searchContent.Description,
|
||||
Body = searchContent.Body,
|
||||
Url = searchContent.Url,
|
||||
Permissions = searchContent.Permissions,
|
||||
ContentModifiedBy = searchContent.ContentModifiedBy,
|
||||
ContentModifiedOn = searchContent.ContentModifiedOn,
|
||||
SearchContentProperties = searchContent.SearchContentProperties,
|
||||
Snippet = BuildSnippet(searchContent, searchQuery),
|
||||
Score = CalculateScore(searchContent, searchQuery)
|
||||
};
|
||||
|
||||
return searchResult;
|
||||
}
|
||||
|
||||
private float CalculateScore(SearchContent searchContent, SearchQuery searchQuery)
|
||||
{
|
||||
var score = 0f;
|
||||
foreach (var keyword in SearchUtils.GetKeywords(searchQuery.Keywords))
|
||||
{
|
||||
score += searchContent.SearchContentWords.Where(i => i.SearchWord.Word.StartsWith(keyword)).Sum(i => i.Count);
|
||||
}
|
||||
|
||||
return score / 100;
|
||||
}
|
||||
|
||||
private string BuildSnippet(SearchContent searchContent, SearchQuery searchQuery)
|
||||
{
|
||||
var content = $"{searchContent.Title} {searchContent.Description} {searchContent.Body}";
|
||||
var snippet = string.Empty;
|
||||
foreach (var keyword in SearchUtils.GetKeywords(searchQuery.Keywords))
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(keyword) && content.Contains(keyword, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var start = content.IndexOf(keyword, StringComparison.OrdinalIgnoreCase) - 20;
|
||||
var prefix = "...";
|
||||
var suffix = "...";
|
||||
if (start <= 0)
|
||||
{
|
||||
start = 0;
|
||||
prefix = string.Empty;
|
||||
}
|
||||
|
||||
var length = searchQuery.BodySnippetLength;
|
||||
if (start + length >= content.Length)
|
||||
{
|
||||
length = content.Length - start;
|
||||
suffix = string.Empty;
|
||||
}
|
||||
|
||||
snippet = $"{prefix}{content.Substring(start, length)}{suffix}";
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(snippet))
|
||||
{
|
||||
snippet = content.Substring(0, searchQuery.BodySnippetLength);
|
||||
}
|
||||
|
||||
foreach (var keyword in SearchUtils.GetKeywords(searchQuery.Keywords))
|
||||
{
|
||||
snippet = Regex.Replace(snippet, $"({keyword})", $"<b>$1</b>", RegexOptions.IgnoreCase);
|
||||
}
|
||||
|
||||
return snippet;
|
||||
}
|
||||
|
||||
private void AnalyzeSearchContent(SearchContent searchContent)
|
||||
{
|
||||
//analyze the search content and save the index words
|
||||
var indexContent = $"{searchContent.Title} {searchContent.Description} {searchContent.Body} {searchContent.AdditionalContent}";
|
||||
var words = GetWords(indexContent, WordMinLength);
|
||||
var existingSearchContentWords = _searchContentRepository.GetSearchContentWords(searchContent.SearchContentId);
|
||||
foreach (var kvp in words)
|
||||
{
|
||||
var searchContentWord = existingSearchContentWords.FirstOrDefault(i => i.SearchWord.Word == kvp.Key);
|
||||
if (searchContentWord != null)
|
||||
{
|
||||
searchContentWord.Count = kvp.Value;
|
||||
searchContentWord.ModifiedOn = DateTime.UtcNow;
|
||||
_searchContentRepository.UpdateSearchContentWord(searchContentWord);
|
||||
}
|
||||
else
|
||||
{
|
||||
var searchWord = _searchContentRepository.GetSearchWord(kvp.Key);
|
||||
if (searchWord == null)
|
||||
{
|
||||
searchWord = _searchContentRepository.AddSearchWord(new SearchWord { Word = kvp.Key, CreatedOn = DateTime.UtcNow });
|
||||
}
|
||||
|
||||
searchContentWord = new SearchContentWord
|
||||
{
|
||||
SearchContentId = searchContent.SearchContentId,
|
||||
SearchWordId = searchWord.SearchWordId,
|
||||
Count = kvp.Value,
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
ModifiedOn = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_searchContentRepository.AddSearchContentWord(searchContentWord);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Dictionary<string, int> GetWords(string content, int minLength)
|
||||
{
|
||||
content = FormatText(content);
|
||||
|
||||
var words = new Dictionary<string, int>();
|
||||
var ignoreWords = IgnoreWords.Split(',');
|
||||
|
||||
if (!string.IsNullOrEmpty(content))
|
||||
{
|
||||
foreach (var word in content.Split(' '))
|
||||
{
|
||||
if (word.Length >= minLength && !ignoreWords.Contains(word))
|
||||
{
|
||||
if (!words.ContainsKey(word))
|
||||
{
|
||||
words.Add(word, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
words[word] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
private static string FormatText(string text)
|
||||
{
|
||||
text = HtmlEntity.DeEntitize(text);
|
||||
foreach (var punctuation in ".?!,;:-_()[]{}'\"/\\".ToCharArray())
|
||||
{
|
||||
text = text.Replace(punctuation, ' ');
|
||||
}
|
||||
text = text.Replace(" ", " ").ToLower().Trim();
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
private void CleanSearchContent(SearchContent searchContent)
|
||||
{
|
||||
searchContent.Title = GetCleanContent(searchContent.Title);
|
||||
searchContent.Description = GetCleanContent(searchContent.Description);
|
||||
searchContent.Body = GetCleanContent(searchContent.Body);
|
||||
searchContent.AdditionalContent = GetCleanContent(searchContent.AdditionalContent);
|
||||
}
|
||||
|
||||
private string GetCleanContent(string content)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(content))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
content = WebUtility.HtmlDecode(content);
|
||||
|
||||
var page = new HtmlDocument();
|
||||
page.LoadHtml(content);
|
||||
|
||||
var phrases = page.DocumentNode.Descendants().Where(i =>
|
||||
i.NodeType == HtmlNodeType.Text &&
|
||||
i.ParentNode.Name != "script" &&
|
||||
i.ParentNode.Name != "style" &&
|
||||
!string.IsNullOrEmpty(i.InnerText.Trim())
|
||||
).Select(i => i.InnerText);
|
||||
|
||||
return string.Join(" ", phrases);
|
||||
}
|
||||
}
|
||||
}
|
@ -29,5 +29,9 @@ namespace Oqtane.Repository
|
||||
public virtual DbSet<Language> Language { get; set; }
|
||||
public virtual DbSet<Visitor> Visitor { get; set; }
|
||||
public virtual DbSet<UrlMapping> UrlMapping { get; set; }
|
||||
public virtual DbSet<SearchContent> SearchContent { get; set; }
|
||||
public virtual DbSet<SearchContentProperty> SearchContentProperty { get; set; }
|
||||
public virtual DbSet<SearchContentWord> SearchContentWord { get; set; }
|
||||
public virtual DbSet<SearchWord> SearchWord { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Oqtane.Models;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public interface ISearchContentRepository
|
||||
{
|
||||
Task<IEnumerable<SearchContent>> GetSearchContentsAsync(SearchQuery searchQuery);
|
||||
SearchContent AddSearchContent(SearchContent searchContent);
|
||||
void DeleteSearchContent(int searchContentId);
|
||||
void DeleteSearchContent(string entityName, string entryId);
|
||||
void DeleteSearchContent(string uniqueKey);
|
||||
void DeleteAllSearchContent();
|
||||
|
||||
SearchWord GetSearchWord(string word);
|
||||
SearchWord AddSearchWord(SearchWord searchWord);
|
||||
|
||||
IEnumerable<SearchContentWord> GetSearchContentWords(int searchContentId);
|
||||
SearchContentWord AddSearchContentWord(SearchContentWord searchContentWord);
|
||||
SearchContentWord UpdateSearchContentWord(SearchContentWord searchContentWord);
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ namespace Oqtane.Repository
|
||||
{
|
||||
IEnumerable<UserRole> GetUserRoles(int siteId);
|
||||
IEnumerable<UserRole> GetUserRoles(int userId, int siteId);
|
||||
IEnumerable<UserRole> GetUserRoles(string roleName, int siteId);
|
||||
UserRole AddUserRole(UserRole userRole);
|
||||
UserRole UpdateUserRole(UserRole userRole);
|
||||
UserRole GetUserRole(int userRoleId);
|
||||
|
@ -59,14 +59,14 @@ namespace Oqtane.Repository
|
||||
// delete logs in batches of 100 records
|
||||
var count = 0;
|
||||
var purgedate = DateTime.UtcNow.AddDays(-age);
|
||||
var logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate)
|
||||
var logs = db.Log.Where(item => item.SiteId == siteId && item.LogDate < purgedate)
|
||||
.OrderBy(item => item.LogDate).Take(100).ToList();
|
||||
while (logs.Count > 0)
|
||||
{
|
||||
count += logs.Count;
|
||||
db.Log.RemoveRange(logs);
|
||||
db.SaveChanges();
|
||||
logs = db.Log.Where(item => item.SiteId == siteId && item.Level != "Error" && item.LogDate < purgedate)
|
||||
logs = db.Log.Where(item => item.SiteId == siteId && item.LogDate < purgedate)
|
||||
.OrderBy(item => item.LogDate).Take(100).ToList();
|
||||
}
|
||||
return count;
|
||||
|
@ -287,7 +287,9 @@ namespace Oqtane.Repository
|
||||
{
|
||||
ModuleDefinition moduledefinition;
|
||||
|
||||
Type[] moduletypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))).ToArray();
|
||||
Type[] modulecontroltypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModuleControl))).ToArray();
|
||||
|
||||
foreach (Type modulecontroltype in modulecontroltypes)
|
||||
{
|
||||
// Check if type should be ignored
|
||||
@ -299,12 +301,9 @@ namespace Oqtane.Repository
|
||||
int index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType);
|
||||
if (index == -1)
|
||||
{
|
||||
// determine if this module implements IModule
|
||||
Type moduletype = assembly
|
||||
.GetTypes()
|
||||
.Where(item => item.Namespace != null)
|
||||
.Where(item => item.Namespace == modulecontroltype.Namespace || item.Namespace.StartsWith(modulecontroltype.Namespace + "."))
|
||||
.FirstOrDefault(item => item.GetInterfaces().Contains(typeof(IModule)));
|
||||
// determine if this component is part of a module which implements IModule
|
||||
Type moduletype = moduletypes.FirstOrDefault(item => item.Namespace == modulecontroltype.Namespace);
|
||||
|
||||
if (moduletype != null)
|
||||
{
|
||||
// get property values from IModule
|
||||
@ -399,6 +398,22 @@ namespace Oqtane.Repository
|
||||
moduledefinitions[index] = moduledefinition;
|
||||
}
|
||||
|
||||
// process modules without UI components
|
||||
foreach (var moduletype in moduletypes.Where(m1 => !modulecontroltypes.Any(m2 => m1.Namespace == m2.Namespace)))
|
||||
{
|
||||
// get property values from IModule
|
||||
var moduleobject = Activator.CreateInstance(moduletype) as IModule;
|
||||
moduledefinition = moduleobject.ModuleDefinition;
|
||||
moduledefinition.ModuleDefinitionName = moduletype.Namespace + ", " + moduletype.Assembly.GetName().Name;
|
||||
moduledefinition.AssemblyName = assembly.GetName().Name;
|
||||
moduledefinition.Categories = "Headless";
|
||||
moduledefinition.PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.Utilize, RoleNames.Host, true)
|
||||
};
|
||||
moduledefinitions.Add(moduledefinition);
|
||||
}
|
||||
|
||||
return moduledefinitions;
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,8 @@ namespace Oqtane.Repository
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var pagemodules = db.PageModule
|
||||
.Include(item => item.Module) // eager load modules
|
||||
.Include(item => item.Module) // eager load module
|
||||
.Include(item => item.Page) // eager load page
|
||||
.Where(item => item.Module.SiteId == siteId).ToList();
|
||||
if (pagemodules.Any())
|
||||
{
|
||||
@ -70,12 +71,16 @@ namespace Oqtane.Repository
|
||||
PageModule pagemodule;
|
||||
if (tracking)
|
||||
{
|
||||
pagemodule = db.PageModule.Include(item => item.Module) // eager load modules
|
||||
pagemodule = db.PageModule
|
||||
.Include(item => item.Module) // eager load module
|
||||
.Include(item => item.Page) // eager load page
|
||||
.FirstOrDefault(item => item.PageModuleId == pageModuleId);
|
||||
}
|
||||
else
|
||||
{
|
||||
pagemodule = db.PageModule.AsNoTracking().Include(item => item.Module) // eager load modules
|
||||
pagemodule = db.PageModule.AsNoTracking()
|
||||
.Include(item => item.Module) // eager load module
|
||||
.Include(item => item.Page) // eager load page
|
||||
.FirstOrDefault(item => item.PageModuleId == pageModuleId);
|
||||
}
|
||||
if (pagemodule != null)
|
||||
@ -90,7 +95,9 @@ namespace Oqtane.Repository
|
||||
public PageModule GetPageModule(int pageId, int moduleId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var pagemodule = db.PageModule.Include(item => item.Module) // eager load modules
|
||||
var pagemodule = db.PageModule
|
||||
.Include(item => item.Module) // eager load module
|
||||
.Include(item => item.Page) // eager load page
|
||||
.SingleOrDefault(item => item.PageId == pageId && item.ModuleId == moduleId);
|
||||
if (pagemodule != null)
|
||||
{
|
||||
@ -104,7 +111,9 @@ namespace Oqtane.Repository
|
||||
public void DeletePageModule(int pageModuleId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var pageModule = db.PageModule.Include(item => item.Module) // eager load modules
|
||||
var pageModule = db.PageModule
|
||||
.Include(item => item.Module) // eager load module
|
||||
.Include(item => item.Page) // eager load page
|
||||
.SingleOrDefault(item => item.PageModuleId == pageModuleId);
|
||||
_settings.DeleteSettings(EntityNames.PageModule, pageModuleId);
|
||||
db.PageModule.Remove(pageModule);
|
||||
@ -140,6 +149,7 @@ namespace Oqtane.Repository
|
||||
}
|
||||
}
|
||||
pageModule.Module.PermissionList = permissions?.ToList();
|
||||
|
||||
return pageModule;
|
||||
}
|
||||
}
|
||||
|
169
Oqtane.Server/Repository/SearchContentRepository.cs
Normal file
169
Oqtane.Server/Repository/SearchContentRepository.cs
Normal file
@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
public class SearchContentRepository : ISearchContentRepository
|
||||
{
|
||||
private readonly IDbContextFactory<TenantDBContext> _dbContextFactory;
|
||||
|
||||
public SearchContentRepository(IDbContextFactory<TenantDBContext> dbContextFactory)
|
||||
{
|
||||
_dbContextFactory = dbContextFactory;
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<SearchContent>> GetSearchContentsAsync(SearchQuery searchQuery)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var searchContents = db.SearchContent.AsNoTracking()
|
||||
.Include(i => i.SearchContentProperties)
|
||||
.Include(i => i.SearchContentWords)
|
||||
.ThenInclude(w => w.SearchWord)
|
||||
.Where(i => i.SiteId == searchQuery.SiteId);
|
||||
|
||||
if (searchQuery.EntityNames != null && searchQuery.EntityNames.Any())
|
||||
{
|
||||
searchContents = searchContents.Where(i => searchQuery.EntityNames.Contains(i.EntityName));
|
||||
}
|
||||
|
||||
if (searchQuery.From != DateTime.MinValue)
|
||||
{
|
||||
searchContents = searchContents.Where(i => i.ContentModifiedOn >= searchQuery.From);
|
||||
}
|
||||
|
||||
if (searchQuery.To != DateTime.MinValue)
|
||||
{
|
||||
searchContents = searchContents.Where(i => i.ContentModifiedOn <= searchQuery.To);
|
||||
}
|
||||
|
||||
if (searchQuery.Properties != null && searchQuery.Properties.Any())
|
||||
{
|
||||
foreach (var property in searchQuery.Properties)
|
||||
{
|
||||
searchContents = searchContents.Where(i => i.SearchContentProperties.Any(p => p.Name == property.Key && p.Value == property.Value));
|
||||
}
|
||||
}
|
||||
|
||||
var filteredContentList = new List<SearchContent>();
|
||||
if (!string.IsNullOrEmpty(searchQuery.Keywords))
|
||||
{
|
||||
foreach (var keyword in SearchUtils.GetKeywords(searchQuery.Keywords))
|
||||
{
|
||||
filteredContentList.AddRange(await searchContents.Where(i => i.SearchContentWords.Any(w => w.SearchWord.Word.StartsWith(keyword))).ToListAsync());
|
||||
}
|
||||
}
|
||||
|
||||
return filteredContentList.DistinctBy(i => i.UniqueKey);
|
||||
}
|
||||
|
||||
public SearchContent AddSearchContent(SearchContent searchContent)
|
||||
{
|
||||
using var context = _dbContextFactory.CreateDbContext();
|
||||
context.SearchContent.Add(searchContent);
|
||||
|
||||
if(searchContent.SearchContentProperties != null && searchContent.SearchContentProperties.Any())
|
||||
{
|
||||
foreach(var property in searchContent.SearchContentProperties)
|
||||
{
|
||||
property.SearchContentId = searchContent.SearchContentId;
|
||||
context.SearchContentProperty.Add(property);
|
||||
}
|
||||
}
|
||||
|
||||
context.SaveChanges();
|
||||
|
||||
return searchContent;
|
||||
}
|
||||
|
||||
public void DeleteSearchContent(int searchContentId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var searchContent = db.SearchContent.Find(searchContentId);
|
||||
db.SearchContent.Remove(searchContent);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
public void DeleteSearchContent(string entityName, string entryId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var searchContent = db.SearchContent.FirstOrDefault(i => i.EntityName == entityName && i.EntityId == entryId);
|
||||
if(searchContent != null)
|
||||
{
|
||||
db.SearchContent.Remove(searchContent);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteSearchContent(string uniqueKey)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
var searchContent = db.SearchContent.FirstOrDefault(i => (i.EntityName + ":" + i.EntityId) == uniqueKey);
|
||||
if (searchContent != null)
|
||||
{
|
||||
db.SearchContent.Remove(searchContent);
|
||||
db.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAllSearchContent()
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
db.SearchContent.RemoveRange(db.SearchContent);
|
||||
db.SaveChanges();
|
||||
}
|
||||
|
||||
public SearchWord GetSearchWord(string word)
|
||||
{
|
||||
if(string.IsNullOrEmpty(word))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
return db.SearchWord.FirstOrDefault(i => i.Word == word);
|
||||
}
|
||||
|
||||
public SearchWord AddSearchWord(SearchWord searchWord)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
|
||||
db.SearchWord.Add(searchWord);
|
||||
db.SaveChanges();
|
||||
|
||||
return searchWord;
|
||||
}
|
||||
|
||||
public IEnumerable<SearchContentWord> GetSearchContentWords(int searchContentId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
return db.SearchContentWord
|
||||
.Include(i => i.SearchWord)
|
||||
.Where(i => i.SearchContentId == searchContentId).ToList();
|
||||
}
|
||||
|
||||
public SearchContentWord AddSearchContentWord(SearchContentWord searchContentWord)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
|
||||
db.SearchContentWord.Add(searchContentWord);
|
||||
db.SaveChanges();
|
||||
|
||||
return searchContentWord;
|
||||
}
|
||||
|
||||
public SearchContentWord UpdateSearchContentWord(SearchContentWord searchContentWord)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
|
||||
db.Entry(searchContentWord).State = EntityState.Modified;
|
||||
db.SaveChanges();
|
||||
|
||||
return searchContentWord;
|
||||
}
|
||||
}
|
||||
}
|
@ -165,22 +165,23 @@ namespace Oqtane.Repository
|
||||
if (!serverstate.IsInitialized)
|
||||
{
|
||||
var site = GetSite(alias.SiteId);
|
||||
|
||||
// initialize theme Assemblies
|
||||
site.Themes = _themeRepository.GetThemes().ToList();
|
||||
|
||||
// initialize module Assemblies
|
||||
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
||||
|
||||
// execute migrations
|
||||
var version = ProcessSiteMigrations(alias, site);
|
||||
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
||||
if (site.Version != version)
|
||||
if (site != null)
|
||||
{
|
||||
site.Version = version;
|
||||
UpdateSite(site);
|
||||
}
|
||||
// initialize theme Assemblies
|
||||
site.Themes = _themeRepository.GetThemes().ToList();
|
||||
|
||||
// initialize module Assemblies
|
||||
var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId);
|
||||
|
||||
// execute migrations
|
||||
var version = ProcessSiteMigrations(alias, site);
|
||||
version = ProcessPageTemplates(alias, site, moduleDefinitions, version);
|
||||
if (site.Version != version)
|
||||
{
|
||||
site.Version = version;
|
||||
UpdateSite(site);
|
||||
}
|
||||
}
|
||||
serverstate.IsInitialized = true;
|
||||
}
|
||||
}
|
||||
@ -328,7 +329,13 @@ namespace Oqtane.Repository
|
||||
}
|
||||
});
|
||||
|
||||
// process site template first
|
||||
// admin site template
|
||||
var siteTemplateType = Type.GetType(Constants.AdminSiteTemplate);
|
||||
var siteTemplateObject = ActivatorUtilities.CreateInstance(_serviceProvider, siteTemplateType);
|
||||
List<PageTemplate> adminPageTemplates = ((ISiteTemplate)siteTemplateObject).CreateSite(site);
|
||||
CreatePages(site, adminPageTemplates, null);
|
||||
|
||||
// process site template
|
||||
if (string.IsNullOrEmpty(site.SiteTemplateType))
|
||||
{
|
||||
var section = _config.GetSection("Installation:SiteTemplate");
|
||||
@ -348,19 +355,16 @@ namespace Oqtane.Repository
|
||||
}
|
||||
}
|
||||
|
||||
Type siteTemplateType = Type.GetType(site.SiteTemplateType);
|
||||
siteTemplateType = Type.GetType(site.SiteTemplateType);
|
||||
if (siteTemplateType != null)
|
||||
{
|
||||
var siteTemplateObject = ActivatorUtilities.CreateInstance(_serviceProvider, siteTemplateType);
|
||||
siteTemplateObject = ActivatorUtilities.CreateInstance(_serviceProvider, siteTemplateType);
|
||||
List<PageTemplate> pageTemplates = ((ISiteTemplate) siteTemplateObject).CreateSite(site);
|
||||
if (pageTemplates != null && pageTemplates.Count > 0)
|
||||
{
|
||||
CreatePages(site, pageTemplates, null);
|
||||
}
|
||||
}
|
||||
|
||||
// create admin pages
|
||||
CreatePages(site, CreateAdminPages(), null);
|
||||
}
|
||||
|
||||
public void CreatePages(Site site, List<PageTemplate> pageTemplates, Alias alias)
|
||||
@ -411,7 +415,7 @@ namespace Oqtane.Repository
|
||||
}
|
||||
else
|
||||
{
|
||||
parent = pages.FirstOrDefault(item => item.Path.ToLower() == pageTemplate.Parent.ToLower());
|
||||
parent = pages.FirstOrDefault(item => item.Path.ToLower() == ((pageTemplate.Parent == "/") ? "" : pageTemplate.Parent.ToLower()));
|
||||
}
|
||||
page.ParentId = (parent != null) ? parent.PageId : null;
|
||||
page.Path = page.Path.ToLower();
|
||||
@ -487,7 +491,11 @@ namespace Oqtane.Repository
|
||||
pageModule.Order = (pageTemplateModule.Order == 0) ? 1 : pageTemplateModule.Order;
|
||||
pageModule.ContainerType = pageTemplateModule.ContainerType;
|
||||
pageModule.IsDeleted = pageTemplateModule.IsDeleted;
|
||||
pageModule.Module.PermissionList = pageTemplateModule.PermissionList;
|
||||
pageModule.Module.PermissionList = new List<Permission>();
|
||||
foreach (var permission in pageTemplateModule.PermissionList)
|
||||
{
|
||||
pageModule.Module.PermissionList.Add(permission.Clone(permission));
|
||||
}
|
||||
pageModule.Module.AllPages = false;
|
||||
pageModule.Module.IsDeleted = false;
|
||||
try
|
||||
@ -539,8 +547,11 @@ namespace Oqtane.Repository
|
||||
try
|
||||
{
|
||||
var module = _moduleRepository.GetModule(pageModule.ModuleId);
|
||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||
((IPortable)moduleobject).ImportModule(module, pageTemplateModule.Content, moduleDefinition.Version);
|
||||
if (module != null)
|
||||
{
|
||||
var moduleobject = ActivatorUtilities.CreateInstance(_serviceProvider, moduletype);
|
||||
((IPortable)moduleobject).ImportModule(module, pageTemplateModule.Content, moduleDefinition.Version);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -564,698 +575,5 @@ namespace Oqtane.Repository
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<PageTemplate> CreateAdminPages(List<PageTemplate> pageTemplates = null)
|
||||
{
|
||||
if (pageTemplates == null) pageTemplates = new List<PageTemplate>();
|
||||
|
||||
// user pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Login",
|
||||
Parent = "",
|
||||
Path = "login",
|
||||
Icon = Icons.LockLocked,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Login.Index).ToModuleDefinitionName(), Title = "User Login", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Register",
|
||||
Parent = "",
|
||||
Path = "register",
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Register.Index).ToModuleDefinitionName(), Title = "User Registration", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Reset",
|
||||
Parent = "",
|
||||
Path = "reset",
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Reset.Index).ToModuleDefinitionName(), Title = "Password Reset", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Profile",
|
||||
Parent = "",
|
||||
Path = "profile",
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UserProfile.Index).ToModuleDefinitionName(), Title = "User Profile", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Not Found",
|
||||
Parent = "",
|
||||
Path = "404",
|
||||
Icon = Icons.X,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", Title = "Not Found", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission> {
|
||||
new Permission(PermissionNames.View, RoleNames.Everyone, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = "<p>The page you requested does not exist or you do not have sufficient rights to view it.</p>"
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// admin pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Admin",
|
||||
Parent = "",
|
||||
Path = "admin",
|
||||
Icon = "",
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Dashboard.Index).ToModuleDefinitionName(), Title = "Admin Dashboard", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Site Settings",
|
||||
Parent = "Admin",
|
||||
Order = 1,
|
||||
Path = "admin/site",
|
||||
Icon = Icons.Home,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Site.Index).ToModuleDefinitionName(), Title = "Site Settings", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Page Management",
|
||||
Parent = "Admin",
|
||||
Order = 3,
|
||||
Path = "admin/pages",
|
||||
Icon = Icons.Layers,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Registered, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Pages.Index).ToModuleDefinitionName(), Title = "Page Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "User Management",
|
||||
Parent = "Admin",
|
||||
Order = 5,
|
||||
Path = "admin/users",
|
||||
Icon = Icons.People,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Users.Index).ToModuleDefinitionName(), Title = "User Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Profile Management",
|
||||
Parent = "Admin",
|
||||
Order = 7,
|
||||
Path = "admin/profiles",
|
||||
Icon = Icons.Person,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Profiles.Index).ToModuleDefinitionName(), Title = "Profile Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Role Management",
|
||||
Parent = "Admin",
|
||||
Order = 9,
|
||||
Path = "admin/roles",
|
||||
Icon = Icons.LockLocked,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Roles.Index).ToModuleDefinitionName(), Title = "Role Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "File Management",
|
||||
Parent = "Admin",
|
||||
Order = 11,
|
||||
Path = "admin/files",
|
||||
Icon = Icons.File,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Files.Index).ToModuleDefinitionName(), Title = "File Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Recycle Bin",
|
||||
Parent = "Admin",
|
||||
Order = 13,
|
||||
Path = "admin/recyclebin",
|
||||
Icon = Icons.Trash,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.RecycleBin.Index).ToModuleDefinitionName(), Title = "Recycle Bin", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Url Mappings",
|
||||
Parent = "Admin",
|
||||
Order = 15,
|
||||
Path = "admin/urlmappings",
|
||||
Icon = Icons.LinkBroken,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.UrlMappings.Index).ToModuleDefinitionName(), Title = "Url Mappings", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Visitor Management",
|
||||
Parent = "Admin",
|
||||
Order = 17,
|
||||
Path = "admin/visitors",
|
||||
Icon = Icons.Eye,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Visitors.Index).ToModuleDefinitionName(), Title = "Visitor Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// host pages
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Event Log",
|
||||
Parent = "Admin",
|
||||
Order = 19,
|
||||
Path = "admin/log",
|
||||
Icon = Icons.MagnifyingGlass,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Logs.Index).ToModuleDefinitionName(), Title = "Event Log", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Site Management",
|
||||
Parent = "Admin",
|
||||
Order = 21,
|
||||
Path = "admin/sites",
|
||||
Icon = Icons.Globe,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sites.Index).ToModuleDefinitionName(), Title = "Site Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Module Management",
|
||||
Parent = "Admin",
|
||||
Order = 23,
|
||||
Path = "admin/modules",
|
||||
Icon = Icons.Browser,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.ModuleDefinitions.Index).ToModuleDefinitionName(), Title = "Module Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Theme Management",
|
||||
Parent = "Admin",
|
||||
Order = 25,
|
||||
Path = "admin/themes",
|
||||
Icon = Icons.Brush,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Themes.Index).ToModuleDefinitionName(), Title = "Theme Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Language Management",
|
||||
Parent = "Admin",
|
||||
Order = 27,
|
||||
Path = "admin/languages",
|
||||
Icon = Icons.Text,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Languages.Index).ToModuleDefinitionName(), Title = "Language Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.View, RoleNames.Admin, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Admin, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Scheduled Jobs",
|
||||
Parent = "Admin",
|
||||
Order = 29,
|
||||
Path = "admin/jobs",
|
||||
Icon = Icons.Timer,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Jobs.Index).ToModuleDefinitionName(), Title = "Scheduled Jobs", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "Sql Management",
|
||||
Parent = "Admin",
|
||||
Order = 31,
|
||||
Path = "admin/sql",
|
||||
Icon = Icons.Spreadsheet,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Sql.Index).ToModuleDefinitionName(), Title = "Sql Management", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "System Info",
|
||||
Parent = "Admin",
|
||||
Order = 33,
|
||||
Path = "admin/system",
|
||||
Icon = Icons.MedicalCross,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.SystemInfo.Index).ToModuleDefinitionName(), Title = "System Info", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
pageTemplates.Add(new PageTemplate
|
||||
{
|
||||
Name = "System Update",
|
||||
Parent = "Admin",
|
||||
Order = 35,
|
||||
Path = "admin/update",
|
||||
Icon = Icons.Aperture,
|
||||
IsNavigation = false,
|
||||
IsPersonalizable = false,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
PageTemplateModules = new List<PageTemplateModule>
|
||||
{
|
||||
new PageTemplateModule
|
||||
{
|
||||
ModuleDefinitionName = typeof(Oqtane.Modules.Admin.Upgrade.Index).ToModuleDefinitionName(), Title = "System Update", Pane = PaneNames.Default,
|
||||
PermissionList = new List<Permission>
|
||||
{
|
||||
new Permission(PermissionNames.View, RoleNames.Host, true),
|
||||
new Permission(PermissionNames.Edit, RoleNames.Host, true)
|
||||
},
|
||||
Content = ""
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return pageTemplates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
@ -35,17 +35,23 @@ namespace Oqtane.Repository
|
||||
|
||||
private List<SiteTemplate> LoadSiteTemplatesFromAssembly(List<SiteTemplate> siteTemplates, Assembly assembly)
|
||||
{
|
||||
SiteTemplate siteTemplate;
|
||||
Type[] siteTemplateTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ISiteTemplate))).ToArray();
|
||||
foreach (Type siteTemplateType in siteTemplateTypes)
|
||||
{
|
||||
var siteTemplateObject = ActivatorUtilities.CreateInstance(_serviceProvider, siteTemplateType);
|
||||
siteTemplate = new SiteTemplate
|
||||
if (siteTemplateObject != null)
|
||||
{
|
||||
Name = (string)siteTemplateType.GetProperty("Name")?.GetValue(siteTemplateObject),
|
||||
TypeName = Utilities.GetFullTypeName(siteTemplateType.AssemblyQualifiedName)
|
||||
};
|
||||
siteTemplates.Add(siteTemplate);
|
||||
var typename = Utilities.GetFullTypeName(siteTemplateType.AssemblyQualifiedName);
|
||||
var name = (string)siteTemplateType.GetProperty("Name")?.GetValue(siteTemplateObject);
|
||||
if (typename != Constants.AdminSiteTemplate && !string.IsNullOrEmpty(name))
|
||||
{
|
||||
siteTemplates.Add(new SiteTemplate
|
||||
{
|
||||
Name = name,
|
||||
TypeName = typename
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return siteTemplates;
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ using Oqtane.Shared;
|
||||
using Oqtane.Themes;
|
||||
using System.Reflection.Metadata;
|
||||
using Oqtane.Migrations.Master;
|
||||
using Oqtane.Modules;
|
||||
|
||||
namespace Oqtane.Repository
|
||||
{
|
||||
@ -224,9 +225,11 @@ namespace Oqtane.Repository
|
||||
private List<Theme> LoadThemesFromAssembly(List<Theme> themes, Assembly assembly)
|
||||
{
|
||||
Theme theme;
|
||||
List<Type> themeTypes = new List<Type>();
|
||||
|
||||
Type[] themeTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))).ToArray();
|
||||
Type[] themeControlTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IThemeControl))).ToArray();
|
||||
Type[] containerControlTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
|
||||
|
||||
foreach (Type themeControlType in themeControlTypes)
|
||||
{
|
||||
// Check if type should be ignored
|
||||
@ -240,16 +243,9 @@ namespace Oqtane.Repository
|
||||
int index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType);
|
||||
if (index == -1)
|
||||
{
|
||||
// Find all types in the assembly with the same namespace root
|
||||
themeTypes = assembly.GetTypes()
|
||||
.Where(item => !item.IsOqtaneIgnore())
|
||||
.Where(item => item.Namespace != null)
|
||||
.Where(item => item.Namespace == themeControlType.Namespace || item.Namespace.StartsWith(themeControlType.Namespace + "."))
|
||||
.ToList();
|
||||
// determine if this component is part of a theme which implements ITheme
|
||||
Type themetype = themeTypes.FirstOrDefault(item => item.Namespace == themeControlType.Namespace);
|
||||
|
||||
// determine if this theme implements ITheme
|
||||
Type themetype = themeTypes
|
||||
.FirstOrDefault(item => item.GetInterfaces().Contains(typeof(ITheme)));
|
||||
if (themetype != null)
|
||||
{
|
||||
var themeobject = Activator.CreateInstance(themetype) as ITheme;
|
||||
@ -285,6 +281,7 @@ namespace Oqtane.Repository
|
||||
}
|
||||
theme = themes[index];
|
||||
|
||||
// add theme control
|
||||
var themecontrolobject = Activator.CreateInstance(themeControlType) as IThemeControl;
|
||||
theme.Themes.Add(
|
||||
new ThemeControl
|
||||
@ -296,14 +293,12 @@ namespace Oqtane.Repository
|
||||
}
|
||||
);
|
||||
|
||||
// containers
|
||||
Type[] containertypes = themeTypes
|
||||
.Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();
|
||||
foreach (Type containertype in containertypes)
|
||||
if (!theme.Containers.Any())
|
||||
{
|
||||
var containerobject = Activator.CreateInstance(containertype) as IThemeControl;
|
||||
if (theme.Containers.FirstOrDefault(item => item.TypeName == containertype.FullName + ", " + themeControlType.Assembly.GetName().Name) == null)
|
||||
// add container controls
|
||||
foreach (Type containertype in containerControlTypes.Where(item => item.Namespace == themeControlType.Namespace))
|
||||
{
|
||||
var containerobject = Activator.CreateInstance(containertype) as IThemeControl;
|
||||
theme.Containers.Add(
|
||||
new ThemeControl
|
||||
{
|
||||
|
@ -23,16 +23,25 @@ namespace Oqtane.Repository
|
||||
return db.UserRole
|
||||
.Include(item => item.Role) // eager load roles
|
||||
.Include(item => item.User) // eager load users
|
||||
.Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null).ToList();
|
||||
.Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<UserRole> GetUserRoles(int userId, int siteId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
return db.UserRole.Where(item => item.UserId == userId)
|
||||
return db.UserRole
|
||||
.Include(item => item.Role) // eager load roles
|
||||
.Include(item => item.User) // eager load users
|
||||
.Where(item => item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1).ToList();
|
||||
.Where(item => (item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1) && item.UserId == userId).ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<UserRole> GetUserRoles(string roleName, int siteId)
|
||||
{
|
||||
using var db = _dbContextFactory.CreateDbContext();
|
||||
return db.UserRole
|
||||
.Include(item => item.Role) // eager load roles
|
||||
.Include(item => item.User) // eager load users
|
||||
.Where(item => (item.Role.SiteId == siteId || item.Role.SiteId == null || siteId == -1) && item.Role.Name == roleName).ToList();
|
||||
}
|
||||
|
||||
public UserRole AddUserRole(UserRole userRole)
|
||||
|
233
Oqtane.Server/Services/SearchService.cs
Normal file
233
Oqtane.Server/Services/SearchService.cs
Normal file
@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Repository;
|
||||
using Oqtane.Security;
|
||||
using Oqtane.Shared;
|
||||
|
||||
namespace Oqtane.Services
|
||||
{
|
||||
public class SearchService : ISearchService
|
||||
{
|
||||
private const string SearchProviderSettingName = "SearchProvider";
|
||||
private const string SearchEnabledSettingName = "SearchEnabled";
|
||||
|
||||
private readonly IServiceProvider _serviceProvider;
|
||||
private readonly ITenantManager _tenantManager;
|
||||
private readonly IAliasRepository _aliasRepository;
|
||||
private readonly ISettingRepository _settingRepository;
|
||||
private readonly IPermissionRepository _permissionRepository;
|
||||
private readonly ILogger<SearchService> _logger;
|
||||
private readonly IMemoryCache _cache;
|
||||
|
||||
public SearchService(
|
||||
IServiceProvider serviceProvider,
|
||||
ITenantManager tenantManager,
|
||||
IAliasRepository aliasRepository,
|
||||
ISettingRepository settingRepository,
|
||||
IPermissionRepository permissionRepository,
|
||||
ILogger<SearchService> logger,
|
||||
IMemoryCache cache)
|
||||
{
|
||||
_tenantManager = tenantManager;
|
||||
_aliasRepository = aliasRepository;
|
||||
_settingRepository = settingRepository;
|
||||
_permissionRepository = permissionRepository;
|
||||
_serviceProvider = serviceProvider;
|
||||
_logger = logger;
|
||||
_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);
|
||||
var searchResults = await searchProvider.SearchAsync(searchQuery, Visible);
|
||||
|
||||
//generate the document url if it's not set.
|
||||
foreach (var result in searchResults.Results)
|
||||
{
|
||||
if(string.IsNullOrEmpty(result.Url))
|
||||
{
|
||||
result.Url = GetDocumentUrl(result, searchQuery);
|
||||
}
|
||||
}
|
||||
|
||||
return searchResults;
|
||||
}
|
||||
|
||||
private ISearchProvider GetSearchProvider(int siteId)
|
||||
{
|
||||
var providerName = GetSearchProviderSetting(siteId);
|
||||
var searchProviders = _serviceProvider.GetServices<ISearchProvider>();
|
||||
var provider = searchProviders.FirstOrDefault(i => i.Name == providerName);
|
||||
if(provider == null)
|
||||
{
|
||||
provider = searchProviders.FirstOrDefault(i => i.Name == Constants.DefaultSearchProviderName);
|
||||
}
|
||||
|
||||
return provider;
|
||||
}
|
||||
|
||||
private string GetSearchProviderSetting(int siteId)
|
||||
{
|
||||
var setting = _settingRepository.GetSetting(EntityNames.Site, siteId, SearchProviderSettingName);
|
||||
if(!string.IsNullOrEmpty(setting?.SettingValue))
|
||||
{
|
||||
return setting.SettingValue;
|
||||
}
|
||||
|
||||
return Constants.DefaultSearchProviderName;
|
||||
}
|
||||
|
||||
private bool SearchEnabled(int siteId)
|
||||
{
|
||||
var setting = _settingRepository.GetSetting(EntityNames.Site, siteId, SearchEnabledSettingName);
|
||||
if (!string.IsNullOrEmpty(setting?.SettingValue))
|
||||
{
|
||||
return bool.TryParse(setting.SettingValue, out bool enabled) && enabled;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetTenant(int siteId)
|
||||
{
|
||||
var alias = _aliasRepository.GetAliases().OrderBy(i => i.SiteId).ThenByDescending(i => i.IsDefault).FirstOrDefault(i => i.SiteId == siteId);
|
||||
_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>();
|
||||
var managerTypes = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => typeof(ISearchResultManager).IsAssignableFrom(p) && !p.IsInterface && !p.IsAbstract);
|
||||
|
||||
foreach (var type in managerTypes)
|
||||
{
|
||||
var manager = (ISearchResultManager)ActivatorUtilities.CreateInstance(_serviceProvider, type);
|
||||
managers.Add(manager);
|
||||
}
|
||||
|
||||
return managers.ToList();
|
||||
}
|
||||
|
||||
private void SaveSearchContent(List<SearchContent> searchContentList)
|
||||
{
|
||||
if(searchContentList.Any())
|
||||
{
|
||||
var searchProvider = GetSearchProvider(searchContentList.First().SiteId);
|
||||
|
||||
foreach (var searchContent in searchContentList)
|
||||
{
|
||||
try
|
||||
{
|
||||
searchProvider.SaveSearchContent(searchContent);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"Search: Save search content {searchContent.UniqueKey} failed.");
|
||||
}
|
||||
}
|
||||
|
||||
//commit the index changes
|
||||
searchProvider.Commit();
|
||||
}
|
||||
}
|
||||
|
||||
private bool Visible(SearchContent searchContent, SearchQuery searchQuery)
|
||||
{
|
||||
var visible = true;
|
||||
foreach (var permission in searchContent.Permissions.Split(','))
|
||||
{
|
||||
var entityName = permission.Split(":")[0];
|
||||
var entityId = int.Parse(permission.Split(":")[1]);
|
||||
if (!HasViewPermission(searchQuery.SiteId, searchQuery.User, entityName, entityId))
|
||||
{
|
||||
visible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return visible;
|
||||
}
|
||||
|
||||
private bool HasViewPermission(int siteId, User user, string entityName, int entityId)
|
||||
{
|
||||
var permissions = _permissionRepository.GetPermissions(siteId, entityName, entityId).ToList();
|
||||
return UserSecurity.IsAuthorized(user, PermissionNames.View, permissions);
|
||||
}
|
||||
|
||||
private string GetDocumentUrl(SearchResult result, SearchQuery searchQuery)
|
||||
{
|
||||
var searchResultManager = GetSearchResultManagers().FirstOrDefault(i => i.Name == result.EntityName);
|
||||
if(searchResultManager != null)
|
||||
{
|
||||
return searchResultManager.GetUrl(result, searchQuery);
|
||||
}
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
@ -62,35 +62,24 @@ namespace Oqtane.Services
|
||||
|
||||
public async Task<Site> GetSiteAsync(int siteId)
|
||||
{
|
||||
if (!_accessor.HttpContext.User.Identity.IsAuthenticated)
|
||||
var alias = _tenantManager.GetAlias();
|
||||
var site = await _cache.GetOrCreateAsync($"site:{alias.SiteKey}", async entry =>
|
||||
{
|
||||
// unauthenticated
|
||||
return await _cache.GetOrCreateAsync($"site:{_accessor.HttpContext.GetAlias().SiteKey}", async entry =>
|
||||
{
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetSite(siteId);
|
||||
}, true);
|
||||
}
|
||||
else // authenticated
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetSite(siteId);
|
||||
});
|
||||
|
||||
var pages = new List<Page>();
|
||||
foreach (Page page in site.Pages)
|
||||
{
|
||||
// is only in registered users role - cache by role
|
||||
if (_accessor.HttpContext.User.IsOnlyInRole(RoleNames.Registered))
|
||||
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)))
|
||||
{
|
||||
return await _cache.GetOrCreateAsync($"site:{_accessor.HttpContext.GetAlias().SiteKey}:{RoleNames.Registered}", async entry =>
|
||||
{
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetSite(siteId);
|
||||
}, true);
|
||||
}
|
||||
else // cache by user
|
||||
{
|
||||
return await _cache.GetOrCreateAsync($"site:{_accessor.HttpContext.GetAlias().SiteKey}:{_accessor.HttpContext.User.UserId()}", async entry =>
|
||||
{
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetSite(siteId);
|
||||
}, true);
|
||||
pages.Add(page);
|
||||
}
|
||||
}
|
||||
site.Pages = pages;
|
||||
|
||||
return site;
|
||||
}
|
||||
|
||||
private async Task<Site> GetSite(int siteid)
|
||||
@ -115,62 +104,17 @@ namespace Oqtane.Services
|
||||
site.Pages = new List<Page>();
|
||||
foreach (Page page in _pages.GetPages(site.SiteId))
|
||||
{
|
||||
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)))
|
||||
{
|
||||
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
site.Pages.Add(page);
|
||||
}
|
||||
page.Settings = settings.Where(item => item.EntityId == page.PageId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, page.PermissionList))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
|
||||
site.Pages.Add(page);
|
||||
}
|
||||
|
||||
site.Pages = GetPagesHierarchy(site.Pages);
|
||||
|
||||
// modules
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(site.SiteId).ToList();
|
||||
settings = _settings.GetSettings(EntityNames.Module).ToList();
|
||||
site.Modules = new List<Module>();
|
||||
foreach (PageModule pagemodule in _pageModules.GetPageModules(site.SiteId).Where(pm => !pm.IsDeleted && _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.View, pm.Module.PermissionList)))
|
||||
{
|
||||
if (Utilities.IsPageModuleVisible(pagemodule.EffectiveDate, pagemodule.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, pagemodule.Module.PermissionList))
|
||||
{
|
||||
Module module = new Module
|
||||
{
|
||||
SiteId = pagemodule.Module.SiteId,
|
||||
ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName,
|
||||
AllPages = pagemodule.Module.AllPages,
|
||||
PermissionList = pagemodule.Module.PermissionList,
|
||||
CreatedBy = pagemodule.Module.CreatedBy,
|
||||
CreatedOn = pagemodule.Module.CreatedOn,
|
||||
ModifiedBy = pagemodule.Module.ModifiedBy,
|
||||
ModifiedOn = pagemodule.Module.ModifiedOn,
|
||||
DeletedBy = pagemodule.DeletedBy,
|
||||
DeletedOn = pagemodule.DeletedOn,
|
||||
IsDeleted = pagemodule.IsDeleted,
|
||||
|
||||
PageModuleId = pagemodule.PageModuleId,
|
||||
ModuleId = pagemodule.ModuleId,
|
||||
PageId = pagemodule.PageId,
|
||||
Title = pagemodule.Title,
|
||||
Pane = pagemodule.Pane,
|
||||
Order = pagemodule.Order,
|
||||
ContainerType = pagemodule.ContainerType,
|
||||
EffectiveDate = pagemodule.EffectiveDate,
|
||||
ExpiryDate = pagemodule.ExpiryDate,
|
||||
|
||||
ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)),
|
||||
|
||||
Settings = settings
|
||||
.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, pagemodule.Module.PermissionList))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue)
|
||||
};
|
||||
|
||||
site.Modules.Add(module);
|
||||
}
|
||||
}
|
||||
|
||||
site.Modules = site.Modules.OrderBy(item => item.PageId).ThenBy(item => item.Pane).ThenBy(item => item.Order).ToList();
|
||||
// framework modules
|
||||
var modules = await GetModulesAsync(site.SiteId);
|
||||
site.Settings.Add(Constants.AdminDashboardModule, modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.AdminDashboardModule).ModuleId.ToString());
|
||||
site.Settings.Add(Constants.PageManagementModule, modules.FirstOrDefault(item => item.ModuleDefinitionName == Constants.PageManagementModule).ModuleId.ToString());
|
||||
|
||||
// languages
|
||||
site.Languages = _languages.GetLanguages(site.SiteId).ToList();
|
||||
@ -191,6 +135,46 @@ namespace Oqtane.Services
|
||||
return site;
|
||||
}
|
||||
|
||||
private static List<Page> GetPagesHierarchy(List<Page> pages)
|
||||
{
|
||||
List<Page> hierarchy = new List<Page>();
|
||||
Action<List<Page>, Page> getPath = null;
|
||||
getPath = (pageList, page) =>
|
||||
{
|
||||
IEnumerable<Page> children;
|
||||
int level;
|
||||
if (page == null)
|
||||
{
|
||||
level = -1;
|
||||
children = pages.Where(item => item.ParentId == null);
|
||||
}
|
||||
else
|
||||
{
|
||||
level = page.Level;
|
||||
children = pages.Where(item => item.ParentId == page.PageId);
|
||||
}
|
||||
foreach (Page child in children)
|
||||
{
|
||||
child.Level = level + 1;
|
||||
child.HasChildren = pages.Any(item => item.ParentId == child.PageId && !item.IsDeleted && item.IsNavigation);
|
||||
hierarchy.Add(child);
|
||||
getPath(pageList, child);
|
||||
}
|
||||
};
|
||||
pages = pages.OrderBy(item => item.Order).ToList();
|
||||
getPath(pages, null);
|
||||
|
||||
// add any non-hierarchical items to the end of the list
|
||||
foreach (Page page in pages)
|
||||
{
|
||||
if (hierarchy.Find(item => item.PageId == page.PageId) == null)
|
||||
{
|
||||
hierarchy.Add(page);
|
||||
}
|
||||
}
|
||||
return hierarchy;
|
||||
}
|
||||
|
||||
public async Task<Site> AddSiteAsync(Site site)
|
||||
{
|
||||
if (_accessor.HttpContext.User.IsInRole(RoleNames.Host))
|
||||
@ -256,44 +240,81 @@ namespace Oqtane.Services
|
||||
}
|
||||
}
|
||||
|
||||
private static List<Page> GetPagesHierarchy(List<Page> pages)
|
||||
public async Task<List<Module>> GetModulesAsync(int siteId, int pageId)
|
||||
{
|
||||
List<Page> hierarchy = new List<Page>();
|
||||
Action<List<Page>, Page> getPath = null;
|
||||
getPath = (pageList, page) =>
|
||||
var alias = _tenantManager.GetAlias();
|
||||
var sitemodules = await _cache.GetOrCreateAsync($"modules:{alias.SiteKey}", async entry =>
|
||||
{
|
||||
IEnumerable<Page> children;
|
||||
int level;
|
||||
if (page == null)
|
||||
{
|
||||
level = -1;
|
||||
children = pages.Where(item => item.ParentId == null);
|
||||
}
|
||||
else
|
||||
{
|
||||
level = page.Level;
|
||||
children = pages.Where(item => item.ParentId == page.PageId);
|
||||
}
|
||||
foreach (Page child in children)
|
||||
{
|
||||
child.Level = level + 1;
|
||||
child.HasChildren = pages.Any(item => item.ParentId == child.PageId && !item.IsDeleted && item.IsNavigation);
|
||||
hierarchy.Add(child);
|
||||
getPath(pageList, child);
|
||||
}
|
||||
};
|
||||
pages = pages.OrderBy(item => item.Order).ToList();
|
||||
getPath(pages, null);
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetModulesAsync(siteId);
|
||||
});
|
||||
|
||||
// add any non-hierarchical items to the end of the list
|
||||
foreach (Page page in pages)
|
||||
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 (hierarchy.Find(item => item.PageId == page.PageId) == null)
|
||||
if (Utilities.IsPageModuleVisible(module.EffectiveDate, module.ExpiryDate) || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, module.PermissionList))
|
||||
{
|
||||
hierarchy.Add(page);
|
||||
modules.Add(module);
|
||||
}
|
||||
}
|
||||
return hierarchy;
|
||||
return modules;
|
||||
}
|
||||
|
||||
public async Task<List<Module>> GetModulesAsync(int siteId)
|
||||
{
|
||||
var alias = _tenantManager.GetAlias();
|
||||
return await _cache.GetOrCreateAsync($"modules:{alias.SiteKey}", async entry =>
|
||||
{
|
||||
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
|
||||
return await GetModules(siteId);
|
||||
});
|
||||
}
|
||||
|
||||
private async Task<List<Module>> GetModules(int siteId)
|
||||
{
|
||||
await Task.Yield(); // force method to async
|
||||
|
||||
List<ModuleDefinition> moduledefinitions = _moduleDefinitions.GetModuleDefinitions(siteId).ToList();
|
||||
var settings = _settings.GetSettings(EntityNames.Module).ToList();
|
||||
var modules = new List<Module>();
|
||||
|
||||
foreach (PageModule pagemodule in _pageModules.GetPageModules(siteId))
|
||||
{
|
||||
Module module = new Module
|
||||
{
|
||||
SiteId = pagemodule.Module.SiteId,
|
||||
ModuleDefinitionName = pagemodule.Module.ModuleDefinitionName,
|
||||
AllPages = pagemodule.Module.AllPages,
|
||||
PermissionList = pagemodule.Module.PermissionList,
|
||||
CreatedBy = pagemodule.Module.CreatedBy,
|
||||
CreatedOn = pagemodule.Module.CreatedOn,
|
||||
ModifiedBy = pagemodule.Module.ModifiedBy,
|
||||
ModifiedOn = pagemodule.Module.ModifiedOn,
|
||||
DeletedBy = pagemodule.DeletedBy,
|
||||
DeletedOn = pagemodule.DeletedOn,
|
||||
IsDeleted = pagemodule.IsDeleted,
|
||||
|
||||
PageModuleId = pagemodule.PageModuleId,
|
||||
ModuleId = pagemodule.ModuleId,
|
||||
PageId = pagemodule.PageId,
|
||||
Title = pagemodule.Title,
|
||||
Pane = pagemodule.Pane,
|
||||
Order = pagemodule.Order,
|
||||
ContainerType = pagemodule.ContainerType,
|
||||
EffectiveDate = pagemodule.EffectiveDate,
|
||||
ExpiryDate = pagemodule.ExpiryDate,
|
||||
|
||||
ModuleDefinition = _moduleDefinitions.FilterModuleDefinition(moduledefinitions.Find(item => item.ModuleDefinitionName == pagemodule.Module.ModuleDefinitionName)),
|
||||
|
||||
Settings = settings.Where(item => item.EntityId == pagemodule.ModuleId)
|
||||
.Where(item => !item.IsPrivate || _userPermissions.IsAuthorized(_accessor.HttpContext.User, PermissionNames.Edit, pagemodule.Module.PermissionList))
|
||||
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue)
|
||||
};
|
||||
|
||||
modules.Add(module);
|
||||
}
|
||||
|
||||
return modules.OrderBy(item => item.PageId).ThenBy(item => item.Pane).ThenBy(item => item.Order).ToList();
|
||||
}
|
||||
|
||||
[Obsolete("This method is deprecated.", false)]
|
||||
|
@ -22,6 +22,7 @@ using Oqtane.UI;
|
||||
using OqtaneSSR.Extensions;
|
||||
using Microsoft.AspNetCore.Components.Authorization;
|
||||
using Oqtane.Providers;
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
|
||||
namespace Oqtane
|
||||
{
|
||||
@ -135,7 +136,7 @@ namespace Oqtane
|
||||
{
|
||||
// allow .NET MAUI client cross origin calls
|
||||
policy.WithOrigins("https://0.0.0.0", "http://0.0.0.0", "app://0.0.0.0")
|
||||
.AllowAnyHeader().AllowCredentials();
|
||||
.AllowAnyHeader().AllowAnyMethod().AllowCredentials();
|
||||
});
|
||||
});
|
||||
|
||||
@ -169,7 +170,7 @@ namespace Oqtane
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ILogger<Startup> logger)
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ISyncManager sync, ICorsService corsService, ICorsPolicyProvider corsPolicyProvider, ILogger<Startup> logger)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_configureServicesErrors))
|
||||
{
|
||||
@ -198,7 +199,16 @@ namespace Oqtane
|
||||
app.UseOqtaneLocalization();
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseStaticFiles();
|
||||
app.UseStaticFiles(new StaticFileOptions
|
||||
{
|
||||
ServeUnknownFileTypes = true,
|
||||
OnPrepareResponse = (ctx) =>
|
||||
{
|
||||
var policy = corsPolicyProvider.GetPolicyAsync(ctx.Context, Constants.MauiCorsPolicy)
|
||||
.ConfigureAwait(false).GetAwaiter().GetResult();
|
||||
corsService.ApplyResult(corsService.EvaluatePolicy(ctx.Context, policy), ctx.Context.Response);
|
||||
}
|
||||
});
|
||||
app.UseExceptionMiddleWare();
|
||||
app.UseTenantResolution();
|
||||
app.UseJwtAuthorization();
|
||||
@ -206,6 +216,7 @@ namespace Oqtane
|
||||
app.UseCors();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseAntiforgery();
|
||||
|
||||
if (_useSwagger)
|
||||
{
|
||||
|
@ -0,0 +1,3 @@
|
||||
.search-result-container ul.pagination li label, .search-result-container ul.dropdown-menu li label {
|
||||
cursor: pointer;
|
||||
}
|
@ -13,9 +13,9 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.6" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Localization" Version="2.2.0" />
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,16 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.Json;
|
||||
using Oqtane.Modules;
|
||||
using Oqtane.Models;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Interfaces;
|
||||
using Oqtane.Enums;
|
||||
using Oqtane.Repository;
|
||||
using [Owner].Module.[Module].Repository;
|
||||
|
||||
namespace [Owner].Module.[Module].Manager
|
||||
{
|
||||
public class [Module]Manager : MigratableModuleBase, IInstallable, IPortable
|
||||
public class [Module]Manager : MigratableModuleBase, IInstallable, IPortable, ISearchable
|
||||
{
|
||||
private readonly I[Module]Repository _[Module]Repository;
|
||||
private readonly IDBContextDependencies _DBContextDependencies;
|
||||
@ -57,5 +59,24 @@ namespace [Owner].Module.[Module].Manager
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<SearchContent> GetSearchContents(Oqtane.Models.Module module, DateTime startTime)
|
||||
{
|
||||
var searchContentList = new List<SearchContent>();
|
||||
|
||||
var [Module]s = _[Module]Repository.Get[Module]s(module.ModuleId);
|
||||
foreach (var [Module] in [Module]s)
|
||||
{
|
||||
searchContentList.Add(new SearchContent
|
||||
{
|
||||
Title = module.Title,
|
||||
Description = string.Empty,
|
||||
Body = [Module].Name,
|
||||
ModifiedTime = [Module].ModifiedOn
|
||||
});
|
||||
}
|
||||
|
||||
return searchContentList;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,10 +19,10 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Title": "Default Module Template",
|
||||
"Type": "External",
|
||||
"Version": "5.1.0",
|
||||
"Version": "5.2.0",
|
||||
"Namespace": "[Owner].Module.[Module]"
|
||||
}
|
||||
|
@ -121,6 +121,49 @@
|
||||
.main .top-row {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.app-search {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.app-search input{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.app-search input + button{
|
||||
position: initial;
|
||||
color: #fff;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.app-search:active, .app-search:hover {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
min-height: 60px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.app-search:active .app-form-inline, .app-search:hover .app-form-inline{
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.app-search:active .app-form-inline input, .app-search:hover .app-form-inline input{
|
||||
width: 100%;
|
||||
display: block !important;
|
||||
}
|
||||
.app-search:active .app-form-inline input + button, .app-search:hover .app-form-inline input + button{
|
||||
position: absolute;
|
||||
color: rgb(42, 159, 214);
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
@ -79,6 +79,10 @@ body {
|
||||
top: -2px;
|
||||
}
|
||||
|
||||
.app-search input{
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.navbar-toggler {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
margin: .5rem;
|
||||
@ -126,4 +130,46 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu
|
||||
position: relative;
|
||||
top: 60px;
|
||||
}
|
||||
.app-search {
|
||||
border-radius: 6px;
|
||||
}
|
||||
.app-search input{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.app-search input + button{
|
||||
position: initial;
|
||||
color: #fff;
|
||||
padding-top: 7px;
|
||||
padding-bottom: 7px;
|
||||
}
|
||||
|
||||
.app-search:active, .app-search:hover {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
min-height: 60px;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
z-index: 999;
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.app-search:active .app-form-inline, .app-search:hover .app-form-inline{
|
||||
margin: 10px auto;
|
||||
position: relative;
|
||||
display: block;
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.app-search:active .app-form-inline input, .app-search:hover .app-form-inline input{
|
||||
width: 100%;
|
||||
display: block !important;
|
||||
}
|
||||
.app-search:active .app-form-inline input + button, .app-search:hover .app-form-inline input + button{
|
||||
position: absolute;
|
||||
color: rgb(42, 159, 214);
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px;
|
||||
}
|
||||
}
|
||||
|
@ -108,12 +108,12 @@
|
||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||
if (_login != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login, true);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Login", _login);
|
||||
}
|
||||
|
||||
if (_register != "-")
|
||||
{
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register, true);
|
||||
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Register", _register);
|
||||
}
|
||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||
}
|
||||
|
@ -9,12 +9,13 @@
|
||||
<Product>[Owner].Theme.[Theme]</Product>
|
||||
<Copyright>[Owner]</Copyright>
|
||||
<AssemblyName>[Owner].Theme.[Theme].Client.Oqtane</AssemblyName>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="8.0.6" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="8.0.6" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -3,6 +3,7 @@
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||
<AccelerateBuildsInVisualStudio>false</AccelerateBuildsInVisualStudio>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"Title": "Default Theme Template",
|
||||
"Type": "External",
|
||||
"Version": "5.1.0",
|
||||
"Version": "5.2.0",
|
||||
"Namespace": "[Owner].Theme.[Theme]"
|
||||
}
|
||||
|
@ -35,6 +35,9 @@ app {
|
||||
}
|
||||
|
||||
/* Action Dialog */
|
||||
.app-actiondialog{
|
||||
position: absolute;
|
||||
}
|
||||
.app-actiondialog .modal {
|
||||
position: fixed; /* Stay in place */
|
||||
z-index: 9999; /* Sit on top */
|
||||
@ -232,3 +235,17 @@ app {
|
||||
.app-form-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
.app-search{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
.app-search input + button{
|
||||
background: none;
|
||||
border: none;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
}
|
||||
.app-search input + button .oi{
|
||||
top: 0;
|
||||
}
|
@ -35,13 +35,15 @@ Oqtane.RichTextEditor = {
|
||||
enableQuillEditor: function (editorElement, mode) {
|
||||
editorElement.__quill.enable(mode);
|
||||
},
|
||||
insertQuillImage: function (quillElement, imageURL, altText) {
|
||||
var Delta = Quill.import('delta');
|
||||
editorIndex = 0;
|
||||
|
||||
getCurrentCursor: function (quillElement) {
|
||||
var editorIndex = 0;
|
||||
if (quillElement.__quill.getSelection() !== null) {
|
||||
editorIndex = quillElement.__quill.getSelection().index;
|
||||
}
|
||||
return editorIndex;
|
||||
},
|
||||
insertQuillImage: function (quillElement, imageURL, altText, editorIndex) {
|
||||
var Delta = Quill.import('delta');
|
||||
|
||||
return quillElement.__quill.updateContents(
|
||||
new Delta()
|
||||
|
Reference in New Issue
Block a user