diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 7a6257ff..8075d4d6 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -8,7 +8,7 @@ @if (_sites == null) { -

Loading...

+

@SharedLocalizer["Loading"]

} else { diff --git a/Oqtane.Client/Program.cs b/Oqtane.Client/Program.cs index e6927c1b..43d23bde 100644 --- a/Oqtane.Client/Program.cs +++ b/Oqtane.Client/Program.cs @@ -9,6 +9,7 @@ using System.Reflection; using System.Runtime.Loader; using System.Text.Json; using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.WebAssembly.Hosting; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.DependencyInjection; @@ -65,6 +66,9 @@ namespace Oqtane.Client private static async Task LoadClientAssemblies(HttpClient http, IServiceProvider serviceProvider) { + var navigationManager = serviceProvider.GetRequiredService(); + var urlpath = GetUrlPath(navigationManager.Uri); + var dlls = new Dictionary(); var pdbs = new Dictionary(); var list = new List(); @@ -76,7 +80,7 @@ namespace Oqtane.Client if (files.Count() != 0) { // get list of assemblies from server - var json = await http.GetStringAsync("/api/Installation/list"); + var json = await http.GetStringAsync($"{urlpath}api/Installation/list"); var assemblies = JsonSerializer.Deserialize>(json); // determine which assemblies need to be downloaded @@ -138,7 +142,7 @@ namespace Oqtane.Client if (list.Count != 0) { // get assemblies from server and load into client app domain - var zip = await http.GetByteArrayAsync($"/api/Installation/load?list=" + string.Join(",", list)); + var zip = await http.GetByteArrayAsync($"{urlpath}api/Installation/load?list=" + string.Join(",", list)); // asemblies and debug symbols are packaged in a zip file using (ZipArchive archive = new ZipArchive(new MemoryStream(zip))) @@ -254,5 +258,12 @@ namespace Oqtane.Client CultureInfo.DefaultThreadCurrentCulture = cultureInfo; CultureInfo.DefaultThreadCurrentUICulture = cultureInfo; } + + private static string GetUrlPath(string url) + { + var path = new Uri(url).AbsolutePath.Substring(1); + path = (!string.IsNullOrEmpty(path) && !path.EndsWith("/")) ? path + "/" : path; + return path; + } } } diff --git a/Oqtane.Client/Services/InstallationService.cs b/Oqtane.Client/Services/InstallationService.cs index 4659d9f6..a9e4d3d6 100644 --- a/Oqtane.Client/Services/InstallationService.cs +++ b/Oqtane.Client/Services/InstallationService.cs @@ -6,6 +6,7 @@ using Oqtane.Shared; using Microsoft.AspNetCore.Components; using System; using System.Net; +using System.Linq; namespace Oqtane.Services { @@ -14,11 +15,13 @@ namespace Oqtane.Services { private readonly NavigationManager _navigationManager; private readonly SiteState _siteState; + private readonly HttpClient _http; public InstallationService(HttpClient http, SiteState siteState, NavigationManager navigationManager) : base(http, siteState) { _navigationManager = navigationManager; _siteState = siteState; + _http = http; } private string ApiUrl => (_siteState.Alias == null) @@ -27,7 +30,15 @@ namespace Oqtane.Services public async Task IsInstalled() { - var path = new Uri(_navigationManager.Uri).LocalPath.Substring(1); + var path = ""; + if (_http.DefaultRequestHeaders.UserAgent.ToString().Contains(Constants.MauiUserAgent)) + { + path = _http.DefaultRequestHeaders.GetValues(Constants.MauiAliasPath).First(); + } + else + { + path = new Uri(_navigationManager.Uri).LocalPath.Substring(1); + } return await GetJsonAsync($"{ApiUrl}/installed/?path={WebUtility.UrlEncode(path)}"); } diff --git a/Oqtane.Client/Services/ServiceBase.cs b/Oqtane.Client/Services/ServiceBase.cs index fb6719a1..fb81b65b 100644 --- a/Oqtane.Client/Services/ServiceBase.cs +++ b/Oqtane.Client/Services/ServiceBase.cs @@ -202,17 +202,27 @@ namespace Oqtane.Services private async Task CheckResponse(HttpResponseMessage response, string uri) { - //if (response.IsSuccessStatusCode && uri.Contains("/api/") && !response.RequestMessage.RequestUri.AbsolutePath.Contains("/api/")) - //{ - // await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Not Mapped To An API Controller Method", uri); - // return false; - //} - if (response.IsSuccessStatusCode) return true; - if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound) + if (response.IsSuccessStatusCode) { - await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Failed With Status {StatusCode} - {ReasonPhrase}", uri, response.StatusCode, response.ReasonPhrase); + // if response from api call is not from an api url then the route was not mapped correctly + if (uri.Contains("/api/") && !response.RequestMessage.RequestUri.AbsolutePath.Contains("/api/")) + { + await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Not Mapped To An API Controller Method", uri); + return false; + } + else + { + return true; + } + } + else + { + if (response.StatusCode != HttpStatusCode.NoContent && response.StatusCode != HttpStatusCode.NotFound) + { + await Log(uri, response.RequestMessage.Method.ToString(), response.StatusCode.ToString(), "Request {Uri} Failed With Status {StatusCode} - {ReasonPhrase}", uri, response.StatusCode, response.ReasonPhrase); + } + return false; } - return false; } private static bool ValidateJsonContent(HttpContent content) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index e1224b16..80c184a0 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -112,8 +112,8 @@ returnurl = WebUtility.UrlDecode(querystring["returnurl"]); } - // reload the client application from the server if there is a forced reload or the user navigated to a site with a different alias - if (querystring.ContainsKey("reload") || (!NavigationManager.ToBaseRelativePath(_absoluteUri).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path))) + // reload the client application from the server if there is a forced reload + if (querystring.ContainsKey("reload")) { if (querystring.ContainsKey("reload") && querystring["reload"] == "post") { diff --git a/Oqtane.Maui/MauiProgram.cs b/Oqtane.Maui/MauiProgram.cs index 93790e14..c76cb732 100644 --- a/Oqtane.Maui/MauiProgram.cs +++ b/Oqtane.Maui/MauiProgram.cs @@ -6,21 +6,21 @@ using Oqtane.Modules; using Oqtane.Services; using System.Globalization; using System.Text.Json; +using Windows.Storage.Provider; namespace Oqtane.Maui; public static class MauiProgram { // the API service url - //static string apiurl = "https://www.dnfprojects.com"; // for testing - static string apiurl = "http://localhost:44357"; // for local development (Oqtane.Server must be already running for MAUI client to connect) - //static string apiurl = "http://localhost:44357/test/"; // for local development (Oqtane.Server must be already running for MAUI client to connect) + //static string apiurl = "https://www.dnfprojects.com/"; // for testing remote site + static string apiurl = "http://localhost:44357/"; // for local development (Oqtane.Server must be already running for MAUI client to connect) + //static string apiurl = "http://localhost:44357/sitename/"; // local microsite example public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); - builder - .UseMauiApp() + builder.UseMauiApp() .ConfigureFonts(fonts => { fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular"); @@ -31,8 +31,9 @@ public static class MauiProgram builder.Services.AddBlazorWebViewDeveloperTools(); #endif - var httpClient = new HttpClient { BaseAddress = new Uri(apiurl) }; + var httpClient = new HttpClient { BaseAddress = new Uri(GetBaseUrl(apiurl)) }; httpClient.DefaultRequestHeaders.UserAgent.ParseAdd(Shared.Constants.MauiUserAgent); + httpClient.DefaultRequestHeaders.Add(Shared.Constants.MauiAliasPath, GetUrlPath(apiurl).Replace("/", "")); builder.Services.AddSingleton(httpClient); builder.Services.AddHttpClient(); // IHttpClientFactory for calling remote services via RemoteServiceBase @@ -85,7 +86,7 @@ public static class MauiProgram if (files.Count() != 0) { // get list of assemblies from server - var json = Task.Run(() => http.GetStringAsync("/api/Installation/list")).GetAwaiter().GetResult(); + var json = Task.Run(() => http.GetStringAsync($"{GetUrlPath(apiurl)}api/Installation/list")).GetAwaiter().GetResult(); var assemblies = JsonSerializer.Deserialize>(json); // determine which assemblies need to be downloaded @@ -149,7 +150,7 @@ public static class MauiProgram if (list.Count != 0) { // get assemblies from server - var zip = Task.Run(() => http.GetByteArrayAsync("/api/Installation/load?list=" + string.Join(",", list))).GetAwaiter().GetResult(); + var zip = Task.Run(() => http.GetByteArrayAsync($"{GetUrlPath(apiurl)}api/Installation/load?list=" + string.Join(",", list))).GetAwaiter().GetResult(); // asemblies and debug symbols are packaged in a zip file using (ZipArchive archive = new ZipArchive(new MemoryStream(zip))) @@ -246,4 +247,17 @@ public static class MauiProgram // could not interrogate assembly - likely missing dependencies } } + + private static string GetBaseUrl(string url) + { + var uri = new Uri(url); + return uri.Scheme + "://"+ uri.Authority + "/"; + } + + private static string GetUrlPath(string url) + { + var path = new Uri(url).AbsolutePath.Substring(1); + path = (!string.IsNullOrEmpty(path) && !path.EndsWith("/")) ? path + "/" : path; + return path; + } } diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index c94163ca..5c439835 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -34,9 +34,9 @@ namespace Oqtane.Controllers private readonly IAliasRepository _aliases; private readonly ILogger _filelogger; private readonly ITenantManager _tenantManager; - private readonly ServerStateManager _serverState; + private readonly IServerStateManager _serverState; - public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger filelogger, ITenantManager tenantManager, ServerStateManager serverState) + public InstallationController(IConfigManager configManager, IInstallationManager installationManager, IDatabaseManager databaseManager, ILocalizationManager localizationManager, IMemoryCache cache, IHttpContextAccessor accessor, IAliasRepository aliases, ILogger filelogger, ITenantManager tenantManager, IServerStateManager serverState) { _configManager = configManager; _installationManager = installationManager; @@ -119,9 +119,9 @@ namespace Oqtane.Controllers private List GetAssemblyList() { - int siteId = _tenantManager.GetAlias().SiteId; + var siteKey = _tenantManager.GetAlias().SiteKey; - return _cache.GetOrCreate($"assemblieslist:{siteId}", entry => + return _cache.GetOrCreate($"assemblieslist:{siteKey}", entry => { var binFolder = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var assemblyList = new List(); @@ -134,7 +134,7 @@ namespace Oqtane.Controllers } // get site assemblies which should be downloaded to client - var assemblies = _serverState.GetServerState(siteId).Assemblies; + var assemblies = _serverState.GetServerState(siteKey).Assemblies; // populate assembly list foreach (var assembly in assemblies) @@ -179,9 +179,11 @@ namespace Oqtane.Controllers private byte[] GetAssemblies(string list) { + var siteKey = _tenantManager.GetAlias().SiteKey; + if (list == "*") { - return _cache.GetOrCreate("assemblies", entry => + return _cache.GetOrCreate($"assemblies:{siteKey}", entry => { return GetZIP(list); }); diff --git a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs index 73c5d9dd..22d04941 100644 --- a/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Server/Extensions/OqtaneServiceCollectionExtensions.cs @@ -62,7 +62,7 @@ namespace Microsoft.Extensions.DependencyInjection services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); return services; } diff --git a/Oqtane.Server/Infrastructure/Interfaces/IServerStateManager.cs b/Oqtane.Server/Infrastructure/Interfaces/IServerStateManager.cs new file mode 100644 index 00000000..48115fe7 --- /dev/null +++ b/Oqtane.Server/Infrastructure/Interfaces/IServerStateManager.cs @@ -0,0 +1,7 @@ +namespace Oqtane.Infrastructure +{ + public interface IServerStateManager + { + ServerState GetServerState(string siteKey); + } +} diff --git a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs index c3386bdd..0c415f85 100644 --- a/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs +++ b/Oqtane.Server/Infrastructure/Middleware/TenantMiddleware.cs @@ -22,6 +22,7 @@ namespace Oqtane.Infrastructure var config = context.RequestServices.GetService(typeof(IConfigManager)) as IConfigManager; string path = context.Request.Path.ToString(); + if (config.IsInstalled() && !path.StartsWith("/_blazor")) { // get alias (note that this also sets SiteState.Alias) @@ -43,6 +44,14 @@ namespace Oqtane.Infrastructure }); context.Items.Add(Constants.HttpContextSiteSettingsKey, sitesettings); + // handle first request to site + var serverState = context.RequestServices.GetService(typeof(IServerStateManager)) as IServerStateManager; + if (!serverState.GetServerState(alias.SiteKey).IsInitialized) + { + var sites = context.RequestServices.GetService(typeof(ISiteRepository)) as ISiteRepository; + sites.InitializeSite(alias); + } + // rewrite path by removing alias path prefix from reserved route (api,pages,files) requests for consistent routes if (!string.IsNullOrEmpty(alias.Path)) { diff --git a/Oqtane.Server/Infrastructure/ServerState.cs b/Oqtane.Server/Infrastructure/ServerState.cs index 6f3ac283..d51e7d17 100644 --- a/Oqtane.Server/Infrastructure/ServerState.cs +++ b/Oqtane.Server/Infrastructure/ServerState.cs @@ -5,9 +5,9 @@ namespace Oqtane.Infrastructure { public class ServerState { - public int SiteId { get; set; } + public string SiteKey { get; set; } public List Assemblies { get; set; } = new List(); public ListScripts { get; set; } = new List(); - public bool IsMigrated { get; set; } = false; + public bool IsInitialized { get; set; } = false; } } diff --git a/Oqtane.Server/Infrastructure/ServerStateManager.cs b/Oqtane.Server/Infrastructure/ServerStateManager.cs index 630ea691..7db90d71 100644 --- a/Oqtane.Server/Infrastructure/ServerStateManager.cs +++ b/Oqtane.Server/Infrastructure/ServerStateManager.cs @@ -5,7 +5,7 @@ using Oqtane.Models; namespace Oqtane.Infrastructure { // singleton - public class ServerStateManager + public class ServerStateManager : IServerStateManager { private List _serverStates { get; set; } @@ -14,36 +14,19 @@ namespace Oqtane.Infrastructure _serverStates = new List(); } - public ServerState GetServerState(int siteId) + public ServerState GetServerState(string siteKey) { - var serverState = _serverStates.FirstOrDefault(item => item.SiteId == siteId); + var serverState = _serverStates.FirstOrDefault(item => item.SiteKey == siteKey); if (serverState == null) { serverState = new ServerState(); - serverState.SiteId = siteId; + serverState.SiteKey = siteKey; serverState.Assemblies = new List(); serverState.Scripts = new List(); - 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; + serverState.IsInitialized = false; _serverStates.Add(serverState); } - else - { - serverstate.Assemblies = serverState.Assemblies; - serverstate.Scripts = serverState.Scripts; - } + return serverState; } } } diff --git a/Oqtane.Server/Infrastructure/TenantManager.cs b/Oqtane.Server/Infrastructure/TenantManager.cs index 226f1d0a..7134e135 100644 --- a/Oqtane.Server/Infrastructure/TenantManager.cs +++ b/Oqtane.Server/Infrastructure/TenantManager.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using Microsoft.AspNetCore.Http; using Oqtane.Models; @@ -57,7 +58,7 @@ namespace Oqtane.Infrastructure alias.BaseUrl = ""; if (httpcontext.Request.Headers.ContainsKey("User-Agent") && httpcontext.Request.Headers["User-Agent"] == Shared.Constants.MauiUserAgent) { - alias.BaseUrl = alias.Protocol + alias.Name; + alias.BaseUrl = alias.Protocol + alias.Name.Replace("/" + alias.Path, ""); } _siteState.Alias = alias; } diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 98b94e13..ddee53c8 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -4,7 +4,6 @@ using Oqtane.Shared; using Oqtane.Models; using System; using System.Linq; -using System.Reflection; using Oqtane.Repository; using Microsoft.AspNetCore.Localization; using Microsoft.Extensions.Configuration; @@ -38,10 +37,11 @@ namespace Oqtane.Pages private readonly IVisitorRepository _visitors; private readonly IAliasRepository _aliases; private readonly ISettingRepository _settings; - private readonly ServerStateManager _serverState; + private readonly IThemeRepository _themes; + private readonly IServerStateManager _serverState; 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, ServerStateManager serverState, 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, IThemeRepository themes, IServerStateManager serverState, ILogManager logger) { _configuration = configuration; _tenantManager = tenantManager; @@ -55,6 +55,7 @@ namespace Oqtane.Pages _visitors = visitors; _aliases = aliases; _settings = settings; + _themes = themes; _serverState = serverState; _logger = logger; } @@ -113,7 +114,7 @@ namespace Oqtane.Pages } } - var site = _sites.InitializeSite(alias); + var site = _sites.GetSite(alias.SiteId); if (site != null && (!site.IsDeleted || url.Contains("admin/site")) && site.Runtime != "Hybrid") { Route route = new Route(url, alias.Path); @@ -167,12 +168,13 @@ namespace Oqtane.Pages } // stylesheets + var themes = _themes.GetThemes().ToList(); var resources = new List(); if (string.IsNullOrEmpty(page.ThemeType)) { page.ThemeType = site.DefaultThemeType; } - var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType)); + var theme = themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == page.ThemeType)); if (theme?.Resources != null) { resources.AddRange(theme.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet).ToList()); @@ -199,7 +201,7 @@ namespace Oqtane.Pages } HeadResources += ParseScripts(site.HeadContent); BodyResources += ParseScripts(site.BodyContent); - var scripts = _serverState.GetServerState(site.SiteId).Scripts; + var scripts = _serverState.GetServerState(alias.SiteKey).Scripts; foreach (var script in scripts) { AddScript(script, alias); diff --git a/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs b/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs index f32123a9..fbba81f9 100644 --- a/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs +++ b/Oqtane.Server/Repository/Interfaces/ISiteRepository.cs @@ -11,7 +11,7 @@ namespace Oqtane.Repository Site GetSite(int siteId); Site GetSite(int siteId, bool tracking); void DeleteSite(int siteId); - Site InitializeSite(Alias alias); + void InitializeSite(Alias alias); void CreatePages(Site site, List pageTemplates, Alias alias); } } diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs index 93d0f7f4..3f2c6de5 100644 --- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs +++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs @@ -21,10 +21,10 @@ namespace Oqtane.Repository private readonly IPermissionRepository _permissions; private readonly ITenantManager _tenants; private readonly ISettingRepository _settings; - private readonly ServerStateManager _serverState; + private readonly IServerStateManager _serverState; private readonly string settingprefix = "SiteEnabled:"; - public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings, ServerStateManager serverState) + public ModuleDefinitionRepository(MasterDBContext context, IMemoryCache cache, IPermissionRepository permissions, ITenantManager tenants, ISettingRepository settings, IServerStateManager serverState) { _db = context; _cache = cache; @@ -179,6 +179,8 @@ namespace Oqtane.Repository if (siteId != -1) { + var siteKey = _tenants.GetAlias().SiteKey; + // get all module definition permissions for site List permissions = _permissions.GetPermissions(siteId, EntityNames.ModuleDefinition).ToList(); @@ -186,7 +188,7 @@ namespace Oqtane.Repository var settings = _settings.GetSettings(EntityNames.ModuleDefinition).ToList(); // populate module definition site settings and permissions - var serverState = _serverState.GetServerState(siteId); + var serverState = _serverState.GetServerState(siteKey); foreach (ModuleDefinition moduledefinition in ModuleDefinitions) { moduledefinition.SiteId = siteId; @@ -251,7 +253,6 @@ namespace Oqtane.Repository } } } - _serverState.SetServerState(siteId, serverState); // clean up any orphaned permissions var ids = new HashSet(ModuleDefinitions.Select(item => item.ModuleDefinitionId)); diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 72b34405..e75738ae 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -27,13 +27,13 @@ namespace Oqtane.Repository private readonly IThemeRepository _themeRepository; private readonly IServiceProvider _serviceProvider; private readonly IConfigurationRoot _config; - private readonly ServerStateManager _serverState; + private readonly IServerStateManager _serverState; private readonly ILogManager _logger; private static readonly object _lock = new object(); public SiteRepository(TenantDBContext context, IRoleRepository roleRepository, IProfileRepository profileRepository, IFolderRepository folderRepository, IPageRepository pageRepository, IModuleRepository moduleRepository, IPageModuleRepository pageModuleRepository, IModuleDefinitionRepository moduleDefinitionRepository, IThemeRepository themeRepository, IServiceProvider serviceProvider, - IConfigurationRoot config, ServerStateManager serverState, ILogManager logger) + IConfigurationRoot config, IServerStateManager serverState, ILogManager logger) { _db = context; _roleRepository = roleRepository; @@ -95,23 +95,25 @@ namespace Oqtane.Repository _db.SaveChanges(); } - public Site InitializeSite(Alias alias) + public void InitializeSite(Alias alias) { - var site = GetSite(alias.SiteId); - - // load themes and module definitions - site.Themes = _themeRepository.GetThemes().ToList(); - var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId); - - // site migrations - var serverstate = _serverState.GetServerState(alias.SiteId); - if (!serverstate.IsMigrated) + var serverstate = _serverState.GetServerState(alias.SiteKey); + if (!serverstate.IsInitialized) { - // ensure migrations are only executed once + // ensure site initialization is only executed once lock (_lock) { - if (!serverstate.IsMigrated) + if (!serverstate.IsInitialized) { + var site = GetSite(alias.SiteId); + + // initialize theme Assemblies and Scripts + site.Themes = _themeRepository.GetThemes().ToList(); + + // initialize module Assemblies and Scripts + var moduleDefinitions = _moduleDefinitionRepository.GetModuleDefinitions(alias.SiteId); + + // execute migrations var version = ProcessSiteMigrations(alias, site); version = ProcessPageTemplates(alias, site, moduleDefinitions, version); if (site.Version != version) @@ -119,13 +121,11 @@ namespace Oqtane.Repository site.Version = version; UpdateSite(site); } - serverstate.IsMigrated = true; - _serverState.SetServerState(alias.SiteId, serverstate); + + serverstate.IsInitialized = true; } } - } - - return site; + } } private string ProcessSiteMigrations(Alias alias, Site site) diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index d34d2f31..5a92e413 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -22,10 +22,10 @@ namespace Oqtane.Repository private readonly IMemoryCache _cache; private readonly ITenantManager _tenants; private readonly ISettingRepository _settings; - private readonly ServerStateManager _serverState; + private readonly IServerStateManager _serverState; private readonly string settingprefix = "SiteEnabled:"; - public ThemeRepository(MasterDBContext context, IMemoryCache cache, ITenantManager tenants, ISettingRepository settings, ServerStateManager serverState) + public ThemeRepository(MasterDBContext context, IMemoryCache cache, ITenantManager tenants, ISettingRepository settings, IServerStateManager serverState) { _db = context; _cache = cache; @@ -157,11 +157,13 @@ namespace Oqtane.Repository if (siteId != -1) { + var siteKey = _tenants.GetAlias().SiteKey; + // get settings for site var settings = _settings.GetSettings(EntityNames.Theme).ToList(); // populate theme site settings - var serverState = _serverState.GetServerState(siteId); + var serverState = _serverState.GetServerState(siteKey); foreach (Theme theme in Themes) { theme.SiteId = siteId; @@ -206,7 +208,6 @@ namespace Oqtane.Repository } } } - _serverState.SetServerState(siteId, serverState); } return Themes; diff --git a/Oqtane.Shared/Models/Alias.cs b/Oqtane.Shared/Models/Alias.cs index c7338576..17ec6e80 100644 --- a/Oqtane.Shared/Models/Alias.cs +++ b/Oqtane.Shared/Models/Alias.cs @@ -70,7 +70,7 @@ namespace Oqtane.Models } /// - /// Protocol for the request from which the alias was resolved (ie. http or https ) + /// Protocol for the request from which the alias was resolved (ie. http:// or https:// ) /// [NotMapped] public string Protocol { get; set; } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 79c7ada9..094591f4 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -79,6 +79,7 @@ namespace Oqtane.Shared public static readonly string HttpContextSiteSettingsKey = "SiteSettings"; public static readonly string MauiUserAgent = "MAUI"; + public static readonly string MauiAliasPath = "Alias-Path"; public static readonly string VisitorCookiePrefix = "APP_VISITOR_"; // Obsolete constants