fix #5005 - adds versioning (ie. fingerprinting) for static assets - core, modules, and themes.
This commit is contained in:
parent
7a9c637e03
commit
153a689bdb
|
@ -391,7 +391,7 @@
|
||||||
if (themetype != null)
|
if (themetype != null)
|
||||||
{
|
{
|
||||||
// get resources for theme (ITheme)
|
// get resources for theme (ITheme)
|
||||||
page.Resources = ManagePageResources(page.Resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName));
|
page.Resources = ManagePageResources(page.Resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), theme.Hash);
|
||||||
|
|
||||||
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
|
||||||
if (themeobject != null)
|
if (themeobject != null)
|
||||||
|
@ -401,7 +401,7 @@
|
||||||
panes = themeobject.Panes;
|
panes = themeobject.Panes;
|
||||||
}
|
}
|
||||||
// get resources for theme control
|
// get resources for theme control
|
||||||
page.Resources = ManagePageResources(page.Resources, themeobject.Resources, ResourceLevel.Page, alias, "Themes", themetype.Namespace);
|
page.Resources = ManagePageResources(page.Resources, themeobject.Resources, ResourceLevel.Page, alias, "Themes", themetype.Namespace, theme.Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// theme settings components are dynamically loaded within the framework Page Management module
|
// theme settings components are dynamically loaded within the framework Page Management module
|
||||||
|
@ -411,7 +411,7 @@
|
||||||
if (settingsType != null)
|
if (settingsType != null)
|
||||||
{
|
{
|
||||||
var objSettings = Activator.CreateInstance(settingsType) as IModuleControl;
|
var objSettings = Activator.CreateInstance(settingsType) as IModuleControl;
|
||||||
page.Resources = ManagePageResources(page.Resources, objSettings.Resources, ResourceLevel.Module, alias, "Modules", settingsType.Namespace);
|
page.Resources = ManagePageResources(page.Resources, objSettings.Resources, ResourceLevel.Module, alias, "Modules", settingsType.Namespace, theme.Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +455,7 @@
|
||||||
|
|
||||||
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
|
||||||
{
|
{
|
||||||
page.Resources = ManagePageResources(page.Resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName));
|
page.Resources = ManagePageResources(page.Resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), module.ModuleDefinition.Hash);
|
||||||
|
|
||||||
// handle default action
|
// handle default action
|
||||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||||
|
@ -504,7 +504,7 @@
|
||||||
module.RenderMode = moduleobject.RenderMode;
|
module.RenderMode = moduleobject.RenderMode;
|
||||||
module.Prerender = moduleobject.Prerender;
|
module.Prerender = moduleobject.Prerender;
|
||||||
|
|
||||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, module.ModuleDefinition?.Hash);
|
||||||
|
|
||||||
// settings components are dynamically loaded within the framework Settings module
|
// settings components are dynamically loaded within the framework Settings module
|
||||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||||
|
@ -525,7 +525,7 @@
|
||||||
if (moduletype != null)
|
if (moduletype != null)
|
||||||
{
|
{
|
||||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, module.ModuleDefinition?.Hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
// container settings component
|
// container settings component
|
||||||
|
@ -536,7 +536,7 @@
|
||||||
if (moduletype != null)
|
if (moduletype != null)
|
||||||
{
|
{
|
||||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace);
|
page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, theme.Hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -595,7 +595,7 @@
|
||||||
return (page, modules);
|
return (page, modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name)
|
private List<Resource> ManagePageResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name, string version)
|
||||||
{
|
{
|
||||||
if (resources != null)
|
if (resources != null)
|
||||||
{
|
{
|
||||||
|
@ -615,7 +615,7 @@
|
||||||
// ensure resource does not exist already
|
// ensure resource does not exist already
|
||||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||||
{
|
{
|
||||||
pageresources.Add(resource.Clone(level, name));
|
pageresources.Add(resource.Clone(level, name, version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<base href="/" />
|
<base href="/" />
|
||||||
<link rel="stylesheet" href="css/app.css" />
|
<link rel="stylesheet" href="css/app.css?v=@_hash" />
|
||||||
@if (_scripts.Contains("PWA Manifest"))
|
@if (_scripts.Contains("PWA Manifest"))
|
||||||
{
|
{
|
||||||
<link id="app-manifest" rel="manifest" />
|
<link id="app-manifest" rel="manifest" />
|
||||||
|
@ -70,15 +70,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
<script src="_framework/blazor.web.js"></script>
|
<script src="_framework/blazor.web.js"></script>
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js?v=@_hash"></script>
|
||||||
<script src="js/loadjs.min.js"></script>
|
<script src="js/loadjs.min.js?v=@_hash"></script>
|
||||||
<script src="js/interop.js"></script>
|
<script src="js/interop.js?v=@_hash"></script>
|
||||||
|
|
||||||
@((MarkupString)_scripts)
|
@((MarkupString)_scripts)
|
||||||
@((MarkupString)_bodyResources)
|
@((MarkupString)_bodyResources)
|
||||||
@if (_renderMode == RenderModes.Static)
|
@if (_renderMode == RenderModes.Static)
|
||||||
{
|
{
|
||||||
<page-script src="./js/reload.js"></page-script>
|
<page-script src="./js/reload.js?v=@_hash"></page-script>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -94,6 +94,7 @@
|
||||||
private string _renderMode = RenderModes.Interactive;
|
private string _renderMode = RenderModes.Interactive;
|
||||||
private string _runtime = Runtimes.Server;
|
private string _runtime = Runtimes.Server;
|
||||||
private bool _prerender = true;
|
private bool _prerender = true;
|
||||||
|
private string _hash = "";
|
||||||
private int _visitorId = -1;
|
private int _visitorId = -1;
|
||||||
private string _antiForgeryToken = "";
|
private string _antiForgeryToken = "";
|
||||||
private string _remoteIPAddress = "";
|
private string _remoteIPAddress = "";
|
||||||
|
@ -136,6 +137,8 @@
|
||||||
_renderMode = site.RenderMode;
|
_renderMode = site.RenderMode;
|
||||||
_runtime = site.Runtime;
|
_runtime = site.Runtime;
|
||||||
_prerender = site.Prerender;
|
_prerender = site.Prerender;
|
||||||
|
_hash = site.Hash;
|
||||||
|
|
||||||
var modules = new List<Module>();
|
var modules = new List<Module>();
|
||||||
|
|
||||||
Route route = new Route(url, alias.Path);
|
Route route = new Route(url, alias.Path);
|
||||||
|
@ -605,13 +608,13 @@
|
||||||
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType));
|
var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType));
|
||||||
if (theme != null)
|
if (theme != null)
|
||||||
{
|
{
|
||||||
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), site.RenderMode);
|
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), theme.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// fallback to default Oqtane theme
|
// fallback to default Oqtane theme
|
||||||
theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == Constants.DefaultTheme));
|
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), site.RenderMode);
|
resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName), theme.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
var type = Type.GetType(themeType);
|
var type = Type.GetType(themeType);
|
||||||
if (type != null)
|
if (type != null)
|
||||||
|
@ -619,7 +622,7 @@
|
||||||
var obj = Activator.CreateInstance(type) as IThemeControl;
|
var obj = Activator.CreateInstance(type) as IThemeControl;
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
{
|
{
|
||||||
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace, site.RenderMode);
|
resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace, theme.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// theme settings components are dynamically loaded within the framework Page Management module
|
// theme settings components are dynamically loaded within the framework Page Management module
|
||||||
|
@ -629,7 +632,7 @@
|
||||||
if (settingsType != null)
|
if (settingsType != null)
|
||||||
{
|
{
|
||||||
var objSettings = Activator.CreateInstance(settingsType) as IModuleControl;
|
var objSettings = Activator.CreateInstance(settingsType) as IModuleControl;
|
||||||
resources = AddResources(resources, objSettings.Resources, ResourceLevel.Module, alias, "Modules", settingsType.Namespace, site.RenderMode);
|
resources = AddResources(resources, objSettings.Resources, ResourceLevel.Module, alias, "Modules", settingsType.Namespace, theme.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -638,7 +641,7 @@
|
||||||
var typename = "";
|
var typename = "";
|
||||||
if (module.ModuleDefinition != null)
|
if (module.ModuleDefinition != null)
|
||||||
{
|
{
|
||||||
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), site.RenderMode);
|
resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName), module.ModuleDefinition.Hash, site.RenderMode);
|
||||||
|
|
||||||
// handle default action
|
// handle default action
|
||||||
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
|
||||||
|
@ -684,7 +687,7 @@
|
||||||
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
if (moduleobject != null)
|
if (moduleobject != null)
|
||||||
{
|
{
|
||||||
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, module.ModuleDefinition?.Hash, site.RenderMode);
|
||||||
|
|
||||||
// settings components are dynamically loaded within the framework Settings module
|
// settings components are dynamically loaded within the framework Settings module
|
||||||
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
if (action.ToLower() == "settings" && module.ModuleDefinition != null)
|
||||||
|
@ -705,7 +708,7 @@
|
||||||
if (moduletype != null)
|
if (moduletype != null)
|
||||||
{
|
{
|
||||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, module.ModuleDefinition?.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// container settings component
|
// container settings component
|
||||||
|
@ -715,7 +718,7 @@
|
||||||
if (moduletype != null)
|
if (moduletype != null)
|
||||||
{
|
{
|
||||||
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
|
||||||
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, site.RenderMode);
|
resources = AddResources(resources, moduleobject.Resources, ResourceLevel.Module, alias, "Modules", moduletype.Namespace, theme.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -731,7 +734,7 @@
|
||||||
{
|
{
|
||||||
if (module.ModuleDefinition?.Resources != null)
|
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);
|
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), module.ModuleDefinition.Hash, site.RenderMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -739,7 +742,7 @@
|
||||||
return resources;
|
return resources;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name, string rendermode)
|
private List<Resource> AddResources(List<Resource> pageresources, List<Resource> resources, ResourceLevel level, Alias alias, string type, string name, string version, string rendermode)
|
||||||
{
|
{
|
||||||
if (resources != null)
|
if (resources != null)
|
||||||
{
|
{
|
||||||
|
@ -759,7 +762,7 @@
|
||||||
// ensure resource does not exist already
|
// ensure resource does not exist already
|
||||||
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower()))
|
||||||
{
|
{
|
||||||
pageresources.Add(resource.Clone(level, name));
|
pageresources.Add(resource.Clone(level, name, version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,7 @@ namespace Oqtane.Controllers
|
||||||
DateTime lastwritetime = System.IO.File.GetLastWriteTime(filepath);
|
DateTime lastwritetime = System.IO.File.GetLastWriteTime(filepath);
|
||||||
if (hashfilename)
|
if (hashfilename)
|
||||||
{
|
{
|
||||||
HashedName = GetDeterministicHashCode(filepath).ToString("X8") + "." + lastwritetime.ToString("yyyyMMddHHmmss") + Path.GetExtension(filepath);
|
HashedName = Utilities.GenerateSimpleHash(filepath) + "." + lastwritetime.ToString("yyyyMMddHHmmss") + Path.GetExtension(filepath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -297,25 +297,5 @@ namespace Oqtane.Controllers
|
||||||
public string FilePath { get; private set; }
|
public string FilePath { get; private set; }
|
||||||
public string HashedName { get; private set; }
|
public string HashedName { get; private set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int GetDeterministicHashCode(string value)
|
|
||||||
{
|
|
||||||
unchecked
|
|
||||||
{
|
|
||||||
int hash1 = (5381 << 16) + 5381;
|
|
||||||
int hash2 = hash1;
|
|
||||||
|
|
||||||
for (int i = 0; i < value.Length; i += 2)
|
|
||||||
{
|
|
||||||
hash1 = ((hash1 << 5) + hash1) ^ value[i];
|
|
||||||
if (i == value.Length - 1)
|
|
||||||
break;
|
|
||||||
hash2 = ((hash2 << 5) + hash2) ^ value[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return hash1 + (hash2 * 1566083941);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ namespace Oqtane.Controllers
|
||||||
if (user != null)
|
if (user != null)
|
||||||
{
|
{
|
||||||
email = user.Email;
|
email = user.Email;
|
||||||
_configManager.AddOrUpdateSetting("PackageRegistryEmail", email, false);
|
_configManager.AddOrUpdateSetting("PackageRegistryEmail", email, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -175,6 +175,12 @@ namespace Oqtane.Infrastructure
|
||||||
installationid = Guid.NewGuid().ToString();
|
installationid = Guid.NewGuid().ToString();
|
||||||
AddOrUpdateSetting("InstallationId", installationid, true);
|
AddOrUpdateSetting("InstallationId", installationid, true);
|
||||||
}
|
}
|
||||||
|
var version = GetSetting("InstallationVersion", "");
|
||||||
|
if (version != Constants.Version)
|
||||||
|
{
|
||||||
|
AddOrUpdateSetting("InstallationVersion", Constants.Version, true);
|
||||||
|
AddOrUpdateSetting("InstallationDate", DateTime.UtcNow.ToString("yyyyMMddHHmm"), true);
|
||||||
|
}
|
||||||
return installationid;
|
return installationid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,6 +265,7 @@ namespace Oqtane.Infrastructure
|
||||||
var installation = IsInstalled();
|
var installation = IsInstalled();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
UpdateInstallation();
|
||||||
UpdateConnectionString(install.ConnectionString);
|
UpdateConnectionString(install.ConnectionString);
|
||||||
UpdateDatabaseType(install.DatabaseType);
|
UpdateDatabaseType(install.DatabaseType);
|
||||||
|
|
||||||
|
@ -491,6 +492,7 @@ namespace Oqtane.Infrastructure
|
||||||
moduleDefinition.Categories = moduledef.Categories;
|
moduleDefinition.Categories = moduledef.Categories;
|
||||||
// update version
|
// update version
|
||||||
moduleDefinition.Version = versions[versions.Length - 1];
|
moduleDefinition.Version = versions[versions.Length - 1];
|
||||||
|
moduleDefinition.ModifiedOn = DateTime.UtcNow;
|
||||||
db.Entry(moduleDefinition).State = EntityState.Modified;
|
db.Entry(moduleDefinition).State = EntityState.Modified;
|
||||||
db.SaveChanges();
|
db.SaveChanges();
|
||||||
}
|
}
|
||||||
|
@ -666,6 +668,11 @@ namespace Oqtane.Infrastructure
|
||||||
return connectionString;
|
return connectionString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateInstallation()
|
||||||
|
{
|
||||||
|
_config.GetInstallationId();
|
||||||
|
}
|
||||||
|
|
||||||
public void UpdateConnectionString(string connectionString)
|
public void UpdateConnectionString(string connectionString)
|
||||||
{
|
{
|
||||||
connectionString = DenormalizeConnectionString(connectionString);
|
connectionString = DenormalizeConnectionString(connectionString);
|
||||||
|
@ -677,7 +684,10 @@ namespace Oqtane.Infrastructure
|
||||||
|
|
||||||
public void UpdateDatabaseType(string databaseType)
|
public void UpdateDatabaseType(string databaseType)
|
||||||
{
|
{
|
||||||
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
|
if (_config.GetSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", "") != databaseType)
|
||||||
|
{
|
||||||
|
_configManager.AddOrUpdateSetting($"{SettingKeys.DatabaseSection}:{SettingKeys.DatabaseTypeKey}", databaseType, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddEFMigrationsHistory(ISqlRepository sql, string connectionString, string databaseType, string version, bool isMaster)
|
public void AddEFMigrationsHistory(ISqlRepository sql, string connectionString, string databaseType, string version, bool isMaster)
|
||||||
|
|
28
Oqtane.Server/Migrations/Master/06000201_AddThemeVersion.cs
Normal file
28
Oqtane.Server/Migrations/Master/06000201_AddThemeVersion.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
using Oqtane.Databases.Interfaces;
|
||||||
|
using Oqtane.Migrations.EntityBuilders;
|
||||||
|
using Oqtane.Repository;
|
||||||
|
|
||||||
|
namespace Oqtane.Migrations.Master
|
||||||
|
{
|
||||||
|
[DbContext(typeof(MasterDBContext))]
|
||||||
|
[Migration("Master.06.00.02.01")]
|
||||||
|
public class AddThemeVersion : MultiDatabaseMigration
|
||||||
|
{
|
||||||
|
public AddThemeVersion(IDatabase database) : base(database)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
var themeEntityBuilder = new ThemeEntityBuilder(migrationBuilder, ActiveDatabase);
|
||||||
|
themeEntityBuilder.AddStringColumn("Version", 50, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
// not implemented
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -101,6 +101,7 @@ namespace Oqtane.Repository
|
||||||
ModuleDefinition.Resources = moduleDefinition.Resources;
|
ModuleDefinition.Resources = moduleDefinition.Resources;
|
||||||
ModuleDefinition.IsEnabled = moduleDefinition.IsEnabled;
|
ModuleDefinition.IsEnabled = moduleDefinition.IsEnabled;
|
||||||
ModuleDefinition.PackageName = moduleDefinition.PackageName;
|
ModuleDefinition.PackageName = moduleDefinition.PackageName;
|
||||||
|
ModuleDefinition.Hash = Utilities.GenerateSimpleHash(moduleDefinition.ModifiedOn.ToString("yyyyMMddHHmm"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ModuleDefinition;
|
return ModuleDefinition;
|
||||||
|
|
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Reflection.Metadata;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.Caching.Memory;
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
using Oqtane.Infrastructure;
|
using Oqtane.Infrastructure;
|
||||||
|
@ -87,6 +88,7 @@ namespace Oqtane.Repository
|
||||||
Theme.ThemeSettingsType = theme.ThemeSettingsType;
|
Theme.ThemeSettingsType = theme.ThemeSettingsType;
|
||||||
Theme.ContainerSettingsType = theme.ContainerSettingsType;
|
Theme.ContainerSettingsType = theme.ContainerSettingsType;
|
||||||
Theme.PackageName = theme.PackageName;
|
Theme.PackageName = theme.PackageName;
|
||||||
|
Theme.Hash = Utilities.GenerateSimpleHash(theme.ModifiedOn.ToString("yyyyMMddHHmm"));
|
||||||
Themes.Add(Theme);
|
Themes.Add(Theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,6 +128,13 @@ namespace Oqtane.Repository
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (theme.Version != Theme.Version)
|
||||||
|
{
|
||||||
|
// update theme version
|
||||||
|
theme.Version = Theme.Version;
|
||||||
|
_db.SaveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
// override user customizable property values
|
// override user customizable property values
|
||||||
Theme.Name = (!string.IsNullOrEmpty(theme.Name)) ? theme.Name : Theme.Name;
|
Theme.Name = (!string.IsNullOrEmpty(theme.Name)) ? theme.Name : Theme.Name;
|
||||||
|
|
||||||
|
|
|
@ -29,12 +29,13 @@ namespace Oqtane.Services
|
||||||
private readonly ISettingRepository _settings;
|
private readonly ISettingRepository _settings;
|
||||||
private readonly ITenantManager _tenantManager;
|
private readonly ITenantManager _tenantManager;
|
||||||
private readonly ISyncManager _syncManager;
|
private readonly ISyncManager _syncManager;
|
||||||
|
private readonly IConfigManager _configManager;
|
||||||
private readonly ILogManager _logger;
|
private readonly ILogManager _logger;
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
private readonly IHttpContextAccessor _accessor;
|
private readonly IHttpContextAccessor _accessor;
|
||||||
private readonly string _private = "[PRIVATE]";
|
private readonly string _private = "[PRIVATE]";
|
||||||
|
|
||||||
public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, ILogManager logger, IMemoryCache cache, IHttpContextAccessor accessor)
|
public ServerSiteService(ISiteRepository sites, IPageRepository pages, IThemeRepository themes, IPageModuleRepository pageModules, IModuleDefinitionRepository moduleDefinitions, ILanguageRepository languages, IUserPermissions userPermissions, ISettingRepository settings, ITenantManager tenantManager, ISyncManager syncManager, IConfigManager configManager, ILogManager logger, IMemoryCache cache, IHttpContextAccessor accessor)
|
||||||
{
|
{
|
||||||
_sites = sites;
|
_sites = sites;
|
||||||
_pages = pages;
|
_pages = pages;
|
||||||
|
@ -46,6 +47,7 @@ namespace Oqtane.Services
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
_tenantManager = tenantManager;
|
_tenantManager = tenantManager;
|
||||||
_syncManager = syncManager;
|
_syncManager = syncManager;
|
||||||
|
_configManager = configManager;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_accessor = accessor;
|
_accessor = accessor;
|
||||||
|
@ -143,6 +145,9 @@ namespace Oqtane.Services
|
||||||
|
|
||||||
// themes
|
// themes
|
||||||
site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList());
|
site.Themes = _themes.FilterThemes(_themes.GetThemes().ToList());
|
||||||
|
|
||||||
|
// installation date used for fingerprinting static assets
|
||||||
|
site.Hash = Utilities.GenerateSimpleHash(_configManager.GetSetting("InstallationDate", DateTime.UtcNow.ToString("yyyyMMddHHmm")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -65,7 +65,7 @@ namespace Oqtane.Models
|
||||||
public string Categories { get; set; }
|
public string Categories { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version information of this Module based on the DLL / NuGet package.
|
/// Version information of this Module based on the information stored in its assembly
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
@ -144,6 +144,9 @@ namespace Oqtane.Models
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsPortable { get; set; }
|
public bool IsPortable { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string Hash { get; set; }
|
||||||
|
|
||||||
#region Deprecated Properties
|
#region Deprecated Properties
|
||||||
|
|
||||||
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
|
[Obsolete("The Permissions property is deprecated. Use PermissionList instead", false)]
|
||||||
|
|
|
@ -83,7 +83,21 @@ namespace Oqtane.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Namespace { get; set; }
|
public string Namespace { get; set; }
|
||||||
|
|
||||||
public Resource Clone(ResourceLevel level, string name)
|
/// <summary>
|
||||||
|
/// The version of the theme or module that declared the resource - only used in SiteRouter
|
||||||
|
/// </summary>
|
||||||
|
public string Version
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(Url) && !Url.Contains("?"))
|
||||||
|
{
|
||||||
|
Url += "?v=" + value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resource Clone(ResourceLevel level, string name, string version)
|
||||||
{
|
{
|
||||||
var resource = new Resource();
|
var resource = new Resource();
|
||||||
resource.ResourceType = ResourceType;
|
resource.ResourceType = ResourceType;
|
||||||
|
@ -106,6 +120,7 @@ namespace Oqtane.Models
|
||||||
}
|
}
|
||||||
resource.Level = level;
|
resource.Level = level;
|
||||||
resource.Namespace = name;
|
resource.Namespace = name;
|
||||||
|
resource.Version = version;
|
||||||
return resource;
|
return resource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,12 @@ namespace Oqtane.Models
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public List<Theme> Themes { get; set; }
|
public List<Theme> Themes { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// hash code for static assets
|
||||||
|
/// </summary>
|
||||||
|
[NotMapped]
|
||||||
|
public string Hash { get; set; }
|
||||||
|
|
||||||
public Site Clone()
|
public Site Clone()
|
||||||
{
|
{
|
||||||
return new Site
|
return new Site
|
||||||
|
@ -227,7 +233,8 @@ namespace Oqtane.Models
|
||||||
Settings = Settings.ToDictionary(setting => setting.Key, setting => setting.Value),
|
Settings = Settings.ToDictionary(setting => setting.Key, setting => setting.Value),
|
||||||
Pages = Pages.ConvertAll(page => page.Clone()),
|
Pages = Pages.ConvertAll(page => page.Clone()),
|
||||||
Languages = Languages.ConvertAll(language => language.Clone()),
|
Languages = Languages.ConvertAll(language => language.Clone()),
|
||||||
Themes = Themes
|
Themes = Themes,
|
||||||
|
Hash = Hash
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,10 +40,13 @@ namespace Oqtane.Models
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
// additional ITheme properties
|
/// <summary>
|
||||||
[NotMapped]
|
/// Version information of this Theme based on the information stored in its assembly
|
||||||
|
/// </summary>
|
||||||
public string Version { get; set; }
|
public string Version { get; set; }
|
||||||
|
|
||||||
|
// additional ITheme properties
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string Owner { get; set; }
|
public string Owner { get; set; }
|
||||||
|
|
||||||
|
@ -78,17 +81,25 @@ namespace Oqtane.Models
|
||||||
// internal properties
|
// internal properties
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public int SiteId { get; set; }
|
public int SiteId { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string AssemblyName { get; set; }
|
public string AssemblyName { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public List<ThemeControl> Themes { get; set; }
|
public List<ThemeControl> Themes { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public List<ThemeControl> Containers { get; set; }
|
public List<ThemeControl> Containers { get; set; }
|
||||||
|
|
||||||
[NotMapped]
|
[NotMapped]
|
||||||
public string Template { get; set; }
|
public string Template { get; set; }
|
||||||
|
|
||||||
|
[NotMapped]
|
||||||
|
public string Hash { get; set; }
|
||||||
|
|
||||||
#region Obsolete Properties
|
#region Obsolete Properties
|
||||||
|
|
||||||
[Obsolete("This property is obsolete. Use Themes instead.", false)]
|
[Obsolete("This property is obsolete. Use Themes instead.", false)]
|
||||||
|
|
|
@ -575,7 +575,6 @@ namespace Oqtane.Shared
|
||||||
}
|
}
|
||||||
else if (expiryDate.HasValue)
|
else if (expiryDate.HasValue)
|
||||||
{
|
{
|
||||||
// Include equality check here
|
|
||||||
return currentUtcTime <= expiryDate.Value;
|
return currentUtcTime <= expiryDate.Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -586,32 +585,40 @@ namespace Oqtane.Shared
|
||||||
|
|
||||||
public static bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate)
|
public static bool ValidateEffectiveExpiryDates(DateTime? effectiveDate, DateTime? expiryDate)
|
||||||
{
|
{
|
||||||
// Treat DateTime.MinValue as null
|
|
||||||
effectiveDate ??= DateTime.MinValue;
|
effectiveDate ??= DateTime.MinValue;
|
||||||
expiryDate ??= DateTime.MinValue;
|
expiryDate ??= DateTime.MinValue;
|
||||||
|
|
||||||
// Check if both effectiveDate and expiryDate have values
|
|
||||||
if (effectiveDate != DateTime.MinValue && expiryDate != DateTime.MinValue)
|
if (effectiveDate != DateTime.MinValue && expiryDate != DateTime.MinValue)
|
||||||
{
|
{
|
||||||
return effectiveDate <= expiryDate;
|
return effectiveDate <= expiryDate;
|
||||||
}
|
}
|
||||||
// Check if only effectiveDate has a value
|
|
||||||
else if (effectiveDate != DateTime.MinValue)
|
else if (effectiveDate != DateTime.MinValue)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// Check if only expiryDate has a value
|
|
||||||
else if (expiryDate != DateTime.MinValue)
|
else if (expiryDate != DateTime.MinValue)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
// If neither effectiveDate nor expiryDate has a value, consider the page/module visible
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GenerateSimpleHash(string text)
|
||||||
|
{
|
||||||
|
unchecked // prevent overflow exception
|
||||||
|
{
|
||||||
|
int hash = 23;
|
||||||
|
foreach (char c in text)
|
||||||
|
{
|
||||||
|
hash = hash * 31 + c;
|
||||||
|
}
|
||||||
|
return hash.ToString("X8");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)]
|
[Obsolete("ContentUrl(Alias alias, int fileId) is deprecated. Use FileUrl(Alias alias, int fileId) instead.", false)]
|
||||||
public static string ContentUrl(Alias alias, int fileId)
|
public static string ContentUrl(Alias alias, int fileId)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user