optimize client assembly download service, add support for site level scripts
This commit is contained in:
parent
98c2f012ee
commit
95ba87945b
@ -531,10 +531,13 @@
|
|||||||
{
|
{
|
||||||
foreach (var resource in resources)
|
foreach (var resource in resources)
|
||||||
{
|
{
|
||||||
if (!resource.Url.Contains("://") && resource.Url.StartsWith("~/"))
|
if (resource.Url.StartsWith("~"))
|
||||||
{
|
{
|
||||||
// create local path
|
resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/");
|
||||||
resource.Url = resource.Url.Replace("~", alias.BaseUrl + "/" + type + "/" + name);
|
}
|
||||||
|
if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl))
|
||||||
|
{
|
||||||
|
resource.Url = alias.BaseUrl + resource.Url;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure resource does not exist already
|
// ensure resource does not exist already
|
||||||
|
@ -33,8 +33,10 @@ namespace Oqtane.Controllers
|
|||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
private readonly ILogger<InstallationController> _filelogger;
|
private readonly ILogger<InstallationController> _filelogger;
|
||||||
|
private readonly ITenantManager _tenantManager;
|
||||||
|
private readonly ServerStateManager _serverState;
|
||||||
|
|
||||||
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger)
|
public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger<InstallationController> filelogger, ITenantManager tenantManager, ServerStateManager serverState)
|
||||||
{
|
{
|
||||||
_configManager = configManager;
|
_configManager = configManager;
|
||||||
_installationManager = installationManager;
|
_installationManager = installationManager;
|
||||||
@ -44,6 +46,8 @@ namespace Oqtane.Controllers
|
|||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
_aliases = aliases;
|
_aliases = aliases;
|
||||||
_filelogger = filelogger;
|
_filelogger = filelogger;
|
||||||
|
_tenantManager = tenantManager;
|
||||||
|
_serverState = serverState;
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST api/<controller>
|
// POST api/<controller>
|
||||||
@ -115,7 +119,9 @@ namespace Oqtane.Controllers
|
|||||||
|
|
||||||
private List<ClientAssembly> GetAssemblyList()
|
private List<ClientAssembly> GetAssemblyList()
|
||||||
{
|
{
|
||||||
return _cache.GetOrCreate("assemblieslist", entry =>
|
int siteId = _tenantManager.GetAlias().SiteId;
|
||||||
|
|
||||||
|
return _cache.GetOrCreate($"assemblieslist:{siteId}", entry =>
|
||||||
{
|
{
|
||||||
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||||
var assemblyList = new List<ClientAssembly>();
|
var assemblyList = new List<ClientAssembly>();
|
||||||
@ -126,78 +132,43 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
hashfilename = false;
|
hashfilename = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get list of assemblies which should be downloaded to client
|
|
||||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneClientAssemblies();
|
|
||||||
var list = assemblies.Select(a => a.GetName().Name).ToList();
|
|
||||||
|
|
||||||
// populate assemblies
|
// get site assemblies which should be downloaded to client
|
||||||
for (int i = 0; i < list.Count; i++)
|
var assemblies = _serverState.GetServerState(siteId).Assemblies;
|
||||||
|
|
||||||
|
// populate assembly list
|
||||||
|
foreach (var assembly in assemblies)
|
||||||
{
|
{
|
||||||
assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, list[i] + ".dll"), hashfilename));
|
if (assembly != Constants.ClientId)
|
||||||
|
{
|
||||||
|
var filepath = Path.Combine(binFolder, assembly) + ".dll";
|
||||||
|
if (System.IO.File.Exists(filepath))
|
||||||
|
{
|
||||||
|
assemblyList.Add(new ClientAssembly(Path.Combine(binFolder, assembly + ".dll"), hashfilename));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert satellite assemblies at beginning of list
|
// insert satellite assemblies at beginning of list
|
||||||
foreach (var culture in _localizationManager.GetInstalledCultures())
|
foreach (var culture in _localizationManager.GetInstalledCultures())
|
||||||
{
|
{
|
||||||
var assembliesFolderPath = Path.Combine(binFolder, culture);
|
if (culture != Constants.DefaultCulture)
|
||||||
if (culture == Constants.DefaultCulture)
|
|
||||||
{
|
{
|
||||||
continue;
|
var assembliesFolderPath = Path.Combine(binFolder, culture);
|
||||||
}
|
if (Directory.Exists(assembliesFolderPath))
|
||||||
|
|
||||||
if (Directory.Exists(assembliesFolderPath))
|
|
||||||
{
|
|
||||||
foreach (var resourceFile in Directory.EnumerateFiles(assembliesFolderPath))
|
|
||||||
{
|
{
|
||||||
assemblyList.Insert(0, new ClientAssembly(resourceFile, hashfilename));
|
foreach (var assembly in assemblies)
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert module and theme dependencies at beginning of list
|
|
||||||
foreach (var assembly in assemblies)
|
|
||||||
{
|
|
||||||
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModule))))
|
|
||||||
{
|
|
||||||
var instance = Activator.CreateInstance(type) as IModule;
|
|
||||||
foreach (string name in instance.ModuleDefinition.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
|
|
||||||
{
|
|
||||||
var filepath = Path.Combine(binFolder, name.ToLower().EndsWith(".dll") ? name : name + ".dll");
|
|
||||||
if (System.IO.File.Exists(filepath))
|
|
||||||
{
|
{
|
||||||
if (!assemblyList.Exists(item => item.FilePath == filepath))
|
var filepath = Path.Combine(assembliesFolderPath, assembly) + ".resources.dll";
|
||||||
|
if (System.IO.File.Exists(filepath))
|
||||||
{
|
{
|
||||||
assemblyList.Insert(0, new ClientAssembly(filepath, hashfilename));
|
assemblyList.Insert(0, new ClientAssembly(Path.Combine(assembliesFolderPath, assembly + ".resources.dll"), hashfilename));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_filelogger.LogError(Utilities.LogMessage(this, $"Module {instance.ModuleDefinition.ModuleDefinitionName} Dependency {name}.dll Does Not Exist"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
foreach (var type in assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(ITheme))))
|
|
||||||
{
|
|
||||||
var instance = Activator.CreateInstance(type) as ITheme;
|
|
||||||
foreach (string name in instance.Theme.Dependencies.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Reverse())
|
|
||||||
{
|
{
|
||||||
var filepath = Path.Combine(binFolder, name.ToLower().EndsWith(".dll") ? name : name + ".dll");
|
_filelogger.LogError(Utilities.LogMessage(this, $"The Satellite Assembly Folder For {culture} Does Not Exist"));
|
||||||
if (System.IO.File.Exists(filepath))
|
|
||||||
{
|
|
||||||
if (!assemblyList.Exists(item => item.FilePath == filepath))
|
|
||||||
{
|
|
||||||
assemblyList.Insert(0, new ClientAssembly(filepath, hashfilename));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_filelogger.LogError(Utilities.LogMessage(this, $"Theme {instance.Theme.ThemeName} Dependency {name}.dll Does Not Exist"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,21 +211,24 @@ namespace Oqtane.Controllers
|
|||||||
{
|
{
|
||||||
foreach (var assembly in assemblies)
|
foreach (var assembly in assemblies)
|
||||||
{
|
{
|
||||||
if (System.IO.File.Exists(assembly.FilePath))
|
if (Path.GetFileNameWithoutExtension(assembly.FilePath) != Constants.ClientId)
|
||||||
{
|
{
|
||||||
using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read))
|
if (System.IO.File.Exists(assembly.FilePath))
|
||||||
using (var entrystream = archive.CreateEntry(assembly.HashedName).Open())
|
|
||||||
{
|
{
|
||||||
filestream.CopyTo(entrystream);
|
using (var filestream = new FileStream(assembly.FilePath, FileMode.Open, FileAccess.Read))
|
||||||
|
using (var entrystream = archive.CreateEntry(assembly.HashedName).Open())
|
||||||
|
{
|
||||||
|
filestream.CopyTo(entrystream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
var pdb = assembly.FilePath.Replace(".dll", ".pdb");
|
||||||
var pdb = assembly.FilePath.Replace(".dll", ".pdb");
|
if (System.IO.File.Exists(pdb))
|
||||||
if (System.IO.File.Exists(pdb))
|
|
||||||
{
|
|
||||||
using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read))
|
|
||||||
using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open())
|
|
||||||
{
|
{
|
||||||
filestream.CopyTo(entrystream);
|
using (var filestream = new FileStream(pdb, FileMode.Open, FileAccess.Read))
|
||||||
|
using (var entrystream = archive.CreateEntry(assembly.HashedName.Replace(".dll", ".pdb")).Open())
|
||||||
|
{
|
||||||
|
filestream.CopyTo(entrystream);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,7 @@ namespace Microsoft.Extensions.DependencyInjection
|
|||||||
services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
|
services.AddSingleton<ILoggerProvider, FileLoggerProvider>();
|
||||||
services.AddSingleton<AutoValidateAntiforgeryTokenFilter>();
|
services.AddSingleton<AutoValidateAntiforgeryTokenFilter>();
|
||||||
services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
|
services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();
|
||||||
|
services.AddSingleton<ServerStateManager>();
|
||||||
return services;
|
return services;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
Oqtane.Server/Infrastructure/ServerState.cs
Normal file
12
Oqtane.Server/Infrastructure/ServerState.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
public class ServerState
|
||||||
|
{
|
||||||
|
public int SiteId { get; set; }
|
||||||
|
public List<string> Assemblies { get; set; } = new List<string>();
|
||||||
|
public List<Resource>Scripts { get; set; } = new List<Resource>();
|
||||||
|
}
|
||||||
|
}
|
49
Oqtane.Server/Infrastructure/ServerStateManager.cs
Normal file
49
Oqtane.Server/Infrastructure/ServerStateManager.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Oqtane.Models;
|
||||||
|
|
||||||
|
namespace Oqtane.Infrastructure
|
||||||
|
{
|
||||||
|
// singleton
|
||||||
|
public class ServerStateManager
|
||||||
|
{
|
||||||
|
private List<ServerState> _serverStates { get; set; }
|
||||||
|
|
||||||
|
public ServerStateManager()
|
||||||
|
{
|
||||||
|
_serverStates = new List<ServerState>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServerState GetServerState(int siteId)
|
||||||
|
{
|
||||||
|
var serverState = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
||||||
|
if (serverState == null)
|
||||||
|
{
|
||||||
|
serverState = new ServerState();
|
||||||
|
serverState.SiteId = siteId;
|
||||||
|
serverState.Assemblies = new List<string>();
|
||||||
|
serverState.Scripts = new List<Resource>();
|
||||||
|
return serverState;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return serverState;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetServerState(int siteId, ServerState serverState)
|
||||||
|
{
|
||||||
|
var serverstate = _serverStates.FirstOrDefault(item => item.SiteId == siteId);
|
||||||
|
if (serverstate == null)
|
||||||
|
{
|
||||||
|
serverState.SiteId = siteId;
|
||||||
|
_serverStates.Add(serverState);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
serverstate.Assemblies = serverState.Assemblies;
|
||||||
|
serverstate.Scripts = serverState.Scripts;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -36,9 +36,10 @@ namespace Oqtane.Pages
|
|||||||
private readonly IVisitorRepository _visitors;
|
private readonly IVisitorRepository _visitors;
|
||||||
private readonly IAliasRepository _aliases;
|
private readonly IAliasRepository _aliases;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
|
private readonly ServerStateManager _serverState;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
|
|
||||||
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ILogManager logger)
|
public HostModel(IConfigManager configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, IJwtManager jwtManager, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases, ISettingRepository settings, ServerStateManager serverState, ILogManager logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
_configuration = configuration;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
@ -52,6 +53,7 @@ namespace Oqtane.Pages
|
|||||||
_visitors = visitors;
|
_visitors = visitors;
|
||||||
_aliases = aliases;
|
_aliases = aliases;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_serverState = serverState;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,33 +119,11 @@ namespace Oqtane.Pages
|
|||||||
{
|
{
|
||||||
Runtime = site.Runtime;
|
Runtime = site.Runtime;
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(site.RenderMode))
|
if (!string.IsNullOrEmpty(site.RenderMode))
|
||||||
{
|
{
|
||||||
RenderMode = site.RenderMode;
|
RenderMode = site.RenderMode;
|
||||||
}
|
}
|
||||||
if (Runtime == "Server")
|
|
||||||
{
|
|
||||||
ReconnectScript = CreateReconnectScript();
|
|
||||||
}
|
|
||||||
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
|
||||||
{
|
|
||||||
PWAScript = CreatePWAScript(alias, site, route);
|
|
||||||
}
|
|
||||||
// site level scripts
|
|
||||||
HeadResources += ParseScripts(site.HeadContent);
|
|
||||||
BodyResources += ParseScripts(site.BodyContent);
|
|
||||||
|
|
||||||
// get jwt token for downstream APIs
|
|
||||||
if (User.Identity.IsAuthenticated)
|
|
||||||
{
|
|
||||||
var sitesettings = HttpContext.GetSiteSettings();
|
|
||||||
var secret = sitesettings.GetValue("JwtOptions:Secret", "");
|
|
||||||
if (!string.IsNullOrEmpty(secret))
|
|
||||||
{
|
|
||||||
AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (site.VisitorTracking)
|
if (site.VisitorTracking)
|
||||||
{
|
{
|
||||||
TrackVisitor(site.SiteId);
|
TrackVisitor(site.SiteId);
|
||||||
@ -172,11 +152,33 @@ namespace Oqtane.Pages
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// include global resources
|
// get jwt token for downstream APIs
|
||||||
var assemblies = AppDomain.CurrentDomain.GetOqtaneAssemblies();
|
if (User.Identity.IsAuthenticated)
|
||||||
foreach (Assembly assembly in assemblies)
|
|
||||||
{
|
{
|
||||||
ProcessHostResources(assembly, alias);
|
var sitesettings = HttpContext.GetSiteSettings();
|
||||||
|
var secret = sitesettings.GetValue("JwtOptions:Secret", "");
|
||||||
|
if (!string.IsNullOrEmpty(secret))
|
||||||
|
{
|
||||||
|
AuthorizationToken = _jwtManager.GenerateToken(alias, (ClaimsIdentity)User.Identity, secret, sitesettings.GetValue("JwtOptions:Issuer", ""), sitesettings.GetValue("JwtOptions:Audience", ""), int.Parse(sitesettings.GetValue("JwtOptions:Lifetime", "20")));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// inject scripts
|
||||||
|
if (Runtime == "Server")
|
||||||
|
{
|
||||||
|
ReconnectScript = CreateReconnectScript();
|
||||||
|
}
|
||||||
|
if (site.PwaIsEnabled && site.PwaAppIconFileId != null && site.PwaSplashIconFileId != null)
|
||||||
|
{
|
||||||
|
PWAScript = CreatePWAScript(alias, site, route);
|
||||||
|
}
|
||||||
|
HeadResources += ParseScripts(site.HeadContent);
|
||||||
|
BodyResources += ParseScripts(site.BodyContent);
|
||||||
|
_sites.InitializeSite(site.SiteId); // populates server state
|
||||||
|
var scripts = _serverState.GetServerState(site.SiteId).Scripts;
|
||||||
|
foreach (var script in scripts)
|
||||||
|
{
|
||||||
|
AddScript(script, alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set culture if not specified
|
// set culture if not specified
|
||||||
@ -409,20 +411,6 @@ namespace Oqtane.Pages
|
|||||||
"</script>";
|
"</script>";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessHostResources(Assembly assembly, Alias alias)
|
|
||||||
{
|
|
||||||
var types = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IHostResources)));
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
var obj = Activator.CreateInstance(type) as IHostResources;
|
|
||||||
foreach (var resource in obj.Resources)
|
|
||||||
{
|
|
||||||
resource.Level = ResourceLevel.App;
|
|
||||||
ProcessResource(resource, 0, alias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private string ParseScripts(string headcontent)
|
private string ParseScripts(string headcontent)
|
||||||
{
|
{
|
||||||
// iterate scripts
|
// iterate scripts
|
||||||
@ -439,60 +427,39 @@ namespace Oqtane.Pages
|
|||||||
return scripts;
|
return scripts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessResource(Resource resource, int count, Alias alias)
|
private void AddScript(Resource resource, Alias alias)
|
||||||
{
|
{
|
||||||
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
var script = CreateScript(resource, alias);
|
||||||
switch (resource.ResourceType)
|
if (resource.Location == Shared.ResourceLocation.Head)
|
||||||
{
|
{
|
||||||
case ResourceType.Stylesheet:
|
if (!HeadResources.Contains(script))
|
||||||
if (!HeadResources.Contains(url, StringComparison.OrdinalIgnoreCase))
|
{
|
||||||
{
|
HeadResources += script + Environment.NewLine;
|
||||||
string id = "";
|
}
|
||||||
if (resource.Level == ResourceLevel.Page)
|
|
||||||
{
|
|
||||||
id = "id=\"app-stylesheet-" + resource.Level.ToString().ToLower() + "-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" ";
|
|
||||||
}
|
|
||||||
HeadResources += "<link " + id + "rel=\"stylesheet\" href=\"" + url + "\"" + CrossOrigin(resource.CrossOrigin) + Integrity(resource.Integrity) + " type=\"text/css\"/>" + Environment.NewLine;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ResourceType.Script:
|
|
||||||
if (resource.Location == Shared.ResourceLocation.Body)
|
|
||||||
{
|
|
||||||
if (!BodyResources.Contains(url, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
BodyResources += "<script src=\"" + url + "\"" + CrossOrigin(resource.CrossOrigin) + Integrity(resource.Integrity) + "></script>" + Environment.NewLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (!HeadResources.Contains(resource.Url, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
HeadResources += "<script src=\"" + url + "\"" + CrossOrigin(resource.CrossOrigin) + Integrity(resource.Integrity) + "></script>" + Environment.NewLine;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private string CrossOrigin(string crossorigin)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(crossorigin))
|
|
||||||
{
|
|
||||||
return " crossorigin=\"" + crossorigin + "\"";
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return "";
|
if (!BodyResources.Contains(script))
|
||||||
|
{
|
||||||
|
BodyResources += script + Environment.NewLine;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private string Integrity(string integrity)
|
|
||||||
|
private string CreateScript(Resource resource, Alias alias)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrEmpty(integrity))
|
if (!string.IsNullOrEmpty(resource.Url))
|
||||||
{
|
{
|
||||||
return " integrity=\"" + integrity + "\"";
|
var url = (resource.Url.Contains("://")) ? resource.Url : alias.BaseUrl + resource.Url;
|
||||||
|
return "<script src=\"" + url + "\"" +
|
||||||
|
((!string.IsNullOrEmpty(resource.CrossOrigin)) ? " crossorigin=\"" + resource.CrossOrigin + "\"" : "") +
|
||||||
|
((!string.IsNullOrEmpty(resource.Integrity)) ? " integrity=\"" + resource.Integrity + "\"" : "") +
|
||||||
|
"></script>";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return "";
|
// inline script
|
||||||
|
return "<script>" + resource.Content + "</script>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ namespace Oqtane.Repository
|
|||||||
Site GetSite(int siteId);
|
Site GetSite(int siteId);
|
||||||
Site GetSite(int siteId, bool tracking);
|
Site GetSite(int siteId, bool tracking);
|
||||||
void DeleteSite(int siteId);
|
void DeleteSite(int siteId);
|
||||||
|
void InitializeSite(int siteId);
|
||||||
void CreatePages(Site site, List<PageTemplate> pageTemplates);
|
void CreatePages(Site site, List<PageTemplate> pageTemplates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,14 @@ using System.Diagnostics;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Xml;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
using Oqtane.Models;
|
using Oqtane.Models;
|
||||||
using Oqtane.Modules;
|
using Oqtane.Modules;
|
||||||
using Oqtane.Shared;
|
using Oqtane.Shared;
|
||||||
|
using Oqtane.Themes;
|
||||||
|
|
||||||
namespace Oqtane.Repository
|
namespace Oqtane.Repository
|
||||||
{
|
{
|
||||||
@ -20,15 +22,17 @@ namespace Oqtane.Repository
|
|||||||
private readonly IPermissionRepository _permissions;
|
private readonly IPermissionRepository _permissions;
|
||||||
private readonly ITenantManager _tenants;
|
private readonly ITenantManager _tenants;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
|
private readonly ServerStateManager _serverState;
|
||||||
private readonly string settingprefix = "SiteEnabled:";
|
private readonly string settingprefix = "SiteEnabled:";
|
||||||
|
|
||||||
public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings)
|
public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings, ServerStateManager serverState)
|
||||||
{
|
{
|
||||||
_db = context;
|
_db = context;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_permissions = permissions;
|
_permissions = permissions;
|
||||||
_tenants = tenants;
|
_tenants = tenants;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_serverState = serverState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<ModuleDefinition> GetModuleDefinitions()
|
public IEnumerable<ModuleDefinition> GetModuleDefinitions()
|
||||||
@ -182,6 +186,7 @@ namespace Oqtane.Repository
|
|||||||
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList();
|
||||||
|
|
||||||
// populate module definition site settings and permissions
|
// populate module definition site settings and permissions
|
||||||
|
var serverState = _serverState.GetServerState(siteId);
|
||||||
foreach (ModuleDefinition moduledefinition in ModuleDefinitions)
|
foreach (ModuleDefinition moduledefinition in ModuleDefinitions)
|
||||||
{
|
{
|
||||||
moduledefinition.SiteId = siteId;
|
moduledefinition.SiteId = siteId;
|
||||||
@ -196,6 +201,36 @@ namespace Oqtane.Repository
|
|||||||
moduledefinition.IsEnabled = moduledefinition.IsAutoEnabled;
|
moduledefinition.IsEnabled = moduledefinition.IsAutoEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (moduledefinition.IsEnabled)
|
||||||
|
{
|
||||||
|
// build list of assemblies for site
|
||||||
|
if (!serverState.Assemblies.Contains(moduledefinition.AssemblyName))
|
||||||
|
{
|
||||||
|
serverState.Assemblies.Add(moduledefinition.AssemblyName);
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(moduledefinition.Dependencies))
|
||||||
|
{
|
||||||
|
foreach (var assembly in moduledefinition.Dependencies.Replace(".dll", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Reverse())
|
||||||
|
{
|
||||||
|
if (!serverState.Assemblies.Contains(assembly))
|
||||||
|
{
|
||||||
|
serverState.Assemblies.Insert(0, assembly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// build list of scripts for site
|
||||||
|
if (moduledefinition.Resources != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in moduledefinition.Resources.Where(item => item.Level == ResourceLevel.Site))
|
||||||
|
{
|
||||||
|
if (!serverState.Scripts.Contains(resource))
|
||||||
|
{
|
||||||
|
serverState.Scripts.Add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (permissions.Count == 0)
|
if (permissions.Count == 0)
|
||||||
{
|
{
|
||||||
// no module definition permissions exist for this site
|
// no module definition permissions exist for this site
|
||||||
@ -216,6 +251,7 @@ namespace Oqtane.Repository
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_serverState.SetServerState(siteId, serverState);
|
||||||
|
|
||||||
// clean up any orphaned permissions
|
// clean up any orphaned permissions
|
||||||
var ids = new HashSet<int>(ModuleDefinitions.Select(item => item.ModuleDefinitionId));
|
var ids = new HashSet<int>(ModuleDefinitions.Select(item => item.ModuleDefinitionId));
|
||||||
@ -295,6 +331,16 @@ namespace Oqtane.Repository
|
|||||||
moduledefinition.ModuleDefinitionName = qualifiedModuleType;
|
moduledefinition.ModuleDefinitionName = qualifiedModuleType;
|
||||||
moduledefinition.ControlTypeTemplate = modulecontroltype.Namespace + "." + Constants.ActionToken + ", " + modulecontroltype.Assembly.GetName().Name;
|
moduledefinition.ControlTypeTemplate = modulecontroltype.Namespace + "." + Constants.ActionToken + ", " + modulecontroltype.Assembly.GetName().Name;
|
||||||
moduledefinition.AssemblyName = assembly.GetName().Name;
|
moduledefinition.AssemblyName = assembly.GetName().Name;
|
||||||
|
if (moduledefinition.Resources != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in moduledefinition.Resources)
|
||||||
|
{
|
||||||
|
if (resource.Url.StartsWith("~"))
|
||||||
|
{
|
||||||
|
resource.Url = resource.Url.Replace("~", "/Modules/" + Utilities.GetTypeName(moduledefinition.ModuleDefinitionName) + "/").Replace("//", "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
moduledefinition.IsPortable = false;
|
moduledefinition.IsPortable = false;
|
||||||
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
if (!string.IsNullOrEmpty(moduledefinition.ServerManagerType))
|
||||||
|
@ -24,11 +24,12 @@ namespace Oqtane.Repository
|
|||||||
private readonly IModuleRepository _moduleRepository;
|
private readonly IModuleRepository _moduleRepository;
|
||||||
private readonly IPageModuleRepository _pageModuleRepository;
|
private readonly IPageModuleRepository _pageModuleRepository;
|
||||||
private readonly IModuleDefinitionRepository _moduleDefinitionRepository;
|
private readonly IModuleDefinitionRepository _moduleDefinitionRepository;
|
||||||
|
private readonly IThemeRepository _themeRepository;
|
||||||
private readonly IServiceProvider _serviceProvider;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
private readonly IConfigurationRoot _config;
|
private readonly IConfigurationRoot _config;
|
||||||
|
|
||||||
public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository,
|
public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository,
|
||||||
IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IServiceProvider serviceProvider,
|
IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IThemeRepository themeRepository, IServiceProvider serviceProvider,
|
||||||
IConfigurationRoot config)
|
IConfigurationRoot config)
|
||||||
{
|
{
|
||||||
_db = context;
|
_db = context;
|
||||||
@ -39,6 +40,7 @@ namespace Oqtane.Repository
|
|||||||
_moduleRepository = moduleRepository;
|
_moduleRepository = moduleRepository;
|
||||||
_pageModuleRepository = pageModuleRepository;
|
_pageModuleRepository = pageModuleRepository;
|
||||||
_moduleDefinitionRepository = moduleDefinitionRepository;
|
_moduleDefinitionRepository = moduleDefinitionRepository;
|
||||||
|
_themeRepository = themeRepository;
|
||||||
_serviceProvider = serviceProvider;
|
_serviceProvider = serviceProvider;
|
||||||
_config = config;
|
_config = config;
|
||||||
}
|
}
|
||||||
@ -88,6 +90,12 @@ namespace Oqtane.Repository
|
|||||||
_db.SaveChanges();
|
_db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void InitializeSite(int siteId)
|
||||||
|
{
|
||||||
|
_moduleDefinitionRepository.GetModuleDefinitions(siteId);
|
||||||
|
_themeRepository.GetThemes();
|
||||||
|
}
|
||||||
|
|
||||||
private void CreateSite(Site site)
|
private void CreateSite(Site site)
|
||||||
{
|
{
|
||||||
// create default entities for site
|
// create default entities for site
|
||||||
|
@ -21,14 +21,16 @@ namespace Oqtane.Repository
|
|||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly ITenantManager _tenants;
|
private readonly ITenantManager _tenants;
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
|
private readonly ServerStateManager _serverState;
|
||||||
private readonly string settingprefix = "SiteEnabled:";
|
private readonly string settingprefix = "SiteEnabled:";
|
||||||
|
|
||||||
public ThemeRepository(MasterDBContext context, IMemoryCache cache, ITenantManager tenants, ISettingRepository settings)
|
public ThemeRepository(MasterDBContext context, IMemoryCache cache, ITenantManager tenants, ISettingRepository settings, ServerStateManager serverState)
|
||||||
{
|
{
|
||||||
_db = context;
|
_db = context;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_tenants = tenants;
|
_tenants = tenants;
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
|
_serverState = serverState;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Theme> GetThemes()
|
public IEnumerable<Theme> GetThemes()
|
||||||
@ -147,6 +149,7 @@ namespace Oqtane.Repository
|
|||||||
var settings = _settings.GetSettings(EntityNames.Theme).ToList();
|
var settings = _settings.GetSettings(EntityNames.Theme).ToList();
|
||||||
|
|
||||||
// populate theme site settings
|
// populate theme site settings
|
||||||
|
var serverState = _serverState.GetServerState(siteId);
|
||||||
foreach (Theme theme in Themes)
|
foreach (Theme theme in Themes)
|
||||||
{
|
{
|
||||||
theme.SiteId = siteId;
|
theme.SiteId = siteId;
|
||||||
@ -160,7 +163,38 @@ namespace Oqtane.Repository
|
|||||||
{
|
{
|
||||||
theme.IsEnabled = theme.IsAutoEnabled;
|
theme.IsEnabled = theme.IsAutoEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (theme.IsEnabled)
|
||||||
|
{
|
||||||
|
// build list of assemblies for site
|
||||||
|
if (!serverState.Assemblies.Contains(theme.AssemblyName))
|
||||||
|
{
|
||||||
|
serverState.Assemblies.Add(theme.AssemblyName);
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrEmpty(theme.Dependencies))
|
||||||
|
{
|
||||||
|
foreach (var assembly in theme.Dependencies.Replace(".dll", "").Split(',', StringSplitOptions.RemoveEmptyEntries).Reverse())
|
||||||
|
{
|
||||||
|
if (!serverState.Assemblies.Contains(assembly))
|
||||||
|
{
|
||||||
|
serverState.Assemblies.Insert(0, assembly);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// build list of scripts for site
|
||||||
|
if (theme.Resources != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in theme.Resources.Where(item => item.Level == ResourceLevel.Site))
|
||||||
|
{
|
||||||
|
if (!serverState.Scripts.Contains(resource))
|
||||||
|
{
|
||||||
|
serverState.Scripts.Add(resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_serverState.SetServerState(siteId, serverState);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Themes;
|
return Themes;
|
||||||
@ -225,12 +259,22 @@ namespace Oqtane.Repository
|
|||||||
Version = new Version(1, 0, 0).ToString()
|
Version = new Version(1, 0, 0).ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// set internal properties
|
// set internal properties
|
||||||
theme.ThemeName = qualifiedThemeType;
|
theme.ThemeName = qualifiedThemeType;
|
||||||
theme.Themes = new List<ThemeControl>();
|
theme.Themes = new List<ThemeControl>();
|
||||||
theme.Containers = new List<ThemeControl>();
|
theme.Containers = new List<ThemeControl>();
|
||||||
theme.AssemblyName = assembly.FullName.Split(",")[0];
|
theme.AssemblyName = assembly.FullName.Split(",")[0];
|
||||||
|
if (theme.Resources != null)
|
||||||
|
{
|
||||||
|
foreach (var resource in theme.Resources)
|
||||||
|
{
|
||||||
|
if (resource.Url.StartsWith("~"))
|
||||||
|
{
|
||||||
|
resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(theme.ThemeName) + "/").Replace("//", "/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Debug.WriteLine($"Oqtane Info: Registering Theme {theme.ThemeName}");
|
Debug.WriteLine($"Oqtane Info: Registering Theme {theme.ThemeName}");
|
||||||
themes.Add(theme);
|
themes.Add(theme);
|
||||||
index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType);
|
index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType);
|
||||||
|
@ -3,6 +3,7 @@ namespace Oqtane.Shared
|
|||||||
public enum ResourceLevel
|
public enum ResourceLevel
|
||||||
{
|
{
|
||||||
App,
|
App,
|
||||||
|
Site,
|
||||||
Page,
|
Page,
|
||||||
Module
|
Module
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user