From c21a097fd24c557cccef5c244f4343c52a384755 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Wed, 22 Dec 2021 15:43:59 -0500 Subject: [PATCH] added support for default alias specification, alias auto registration, alias redirect, alias line break delimiters --- Oqtane.Client/Modules/Admin/Site/Index.razor | 438 ++++++++++-------- Oqtane.Client/Modules/Admin/Sites/Add.razor | 2 + Oqtane.Client/Modules/Admin/Sites/Index.razor | 11 +- .../Resources/Modules/Admin/Site/Index.resx | 14 +- Oqtane.Client/Services/SettingService.cs | 2 +- .../Infrastructure/DatabaseManager.cs | 10 +- .../Master/03000201_AddAliasRedirect.cs | 31 ++ Oqtane.Server/Pages/_Host.cshtml.cs | 23 +- Oqtane.Server/Repository/AliasRepository.cs | 17 +- Oqtane.Shared/Models/Alias.cs | 6 + Oqtane.Shared/Models/Route.cs | 2 +- 11 files changed, 329 insertions(+), 227 deletions(-) create mode 100644 Oqtane.Server/Migrations/Master/03000201_AddAliasRedirect.cs diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index fab9fb18..6d8d2dd2 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Admin.Site @inherits ModuleBase +@using System.Text.RegularExpressions @inject NavigationManager NavigationManager @inject ISiteService SiteService @inject ITenantService TenantService @@ -22,81 +23,64 @@
- +
- @if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - - } - else - { - - } +
- +
- + + @foreach (var theme in _themes) + { + + }
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
+
+ +
+
-
+
+ +
+ +
+
+
+ +
+ +
+
+
@@ -176,6 +160,27 @@
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
@@ -238,7 +243,8 @@ private List _themes = new List(); private List _containers = new List(); private string _name = string.Empty; - private List _aliasList; + private List _aliases; + private string _defaultalias = string.Empty; private string _urls = string.Empty; private string _runtime = ""; private string _prerender = ""; @@ -288,13 +294,7 @@ if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { - _aliasList = await AliasService.GetAliasesAsync(); - foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) - { - _urls += alias.Name + ","; - } - _urls = _urls.Substring(0, _urls.Length - 1); - + await GetAliases(); } if (site.LogoFileId != null) @@ -322,7 +322,7 @@ { _pwasplashiconfileid = site.PwaSplashIconFileId.Value; } - + var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); _smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty); _smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty); @@ -395,14 +395,16 @@ { if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-") { + _urls = Regex.Replace(_urls, @"\r\n?|\n", ","); // convert line breaks to commas var unique = true; if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) { - foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray()) { - if (_aliasList.Exists(item => item.Name == name && item.SiteId != PageState.Alias.SiteId && item.TenantId != PageState.Alias.TenantId)) + var alias = _aliases.Where(item => item.Name == name).FirstOrDefault(); + if (alias != null && unique) { - unique = false; + unique = (alias.TenantId == PageState.Site.TenantId && alias.SiteId == PageState.Site.SiteId); } } } @@ -461,145 +463,173 @@ int? pwaappiconfileid = _pwaappiconfilemanager.GetFileId(); if (pwaappiconfileid == -1) pwaappiconfileid = null; if (site.PwaAppIconFileId != pwaappiconfileid) - { - site.PwaAppIconFileId = pwaappiconfileid; + { + site.PwaAppIconFileId = pwaappiconfileid; reload = true; // needs to be reloaded on server - } - int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId(); + } + int? pwasplashiconfileid = _pwasplashiconfilemanager.GetFileId(); if (pwasplashiconfileid == -1) pwasplashiconfileid = null; - if (site.PwaSplashIconFileId != pwasplashiconfileid) - { - site.PwaSplashIconFileId = pwasplashiconfileid; + if (site.PwaSplashIconFileId != pwasplashiconfileid) + { + site.PwaSplashIconFileId = pwasplashiconfileid; reload = true; // needs to be reloaded on server - } + } - site = await SiteService.UpdateSiteAsync(site); + site = await SiteService.UpdateSiteAsync(site); - var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); - SettingService.SetSetting(settings, "SMTPHost", _smtphost, false); - SettingService.SetSetting(settings, "SMTPPort", _smtpport, false); - SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, false); - SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, false); - SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, false); - SettingService.SetSetting(settings, "SMTPSender", _smtpsender, false); - await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); + var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); + SettingService.SetSetting(settings, "SMTPHost", _smtphost, false); + SettingService.SetSetting(settings, "SMTPPort", _smtpport, false); + SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, false); + SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, false); + SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, false); + SettingService.SetSetting(settings, "SMTPSender", _smtpsender, false); + await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); - foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) - { - if (!names.Contains(alias.Name)) - { - await AliasService.DeleteAliasAsync(alias.AliasId); - } - } + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Select(sValue => sValue.Trim()).ToArray(); + foreach (Alias alias in _aliases.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList()) + { + if (!names.Contains(alias.Name)) + { + await AliasService.DeleteAliasAsync(alias.AliasId); + } + } + if (!names.Contains(_defaultalias)) { _defaultalias = names[0]; } - foreach (string name in names) - { - if (!_aliasList.Exists(item => item.Name == name)) - { - Alias alias = new Alias(); - alias.Name = name; - alias.TenantId = site.TenantId; - alias.SiteId = site.SiteId; - await AliasService.AddAliasAsync(alias); - } - } - } + foreach (string name in names) + { + var alias = _aliases.Find(item => item.Name == name); + if (alias == null) + { + alias = new Alias(); + alias.Name = name; + alias.TenantId = site.TenantId; + alias.SiteId = site.SiteId; + alias.IsDefault = (name == _defaultalias); + await AliasService.AddAliasAsync(alias); + } + else + { + if (alias.IsDefault != (alias.Name == _defaultalias)) + { + alias.IsDefault = (name == _defaultalias); + await AliasService.UpdateAliasAsync(alias); + } + } + } + await GetAliases(); + } - await logger.LogInformation("Site Settings Saved {Site}", site); + await logger.LogInformation("Site Settings Saved {Site}", site); - if (refresh) - { - NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload - } - else - { - AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success); - } - } - } - else - { - AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); - } - } - else - { - AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning); - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message); - AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error); - } - } - else - { - AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning); - } - } + if (refresh) + { + NavigationManager.NavigateTo(NavigateUrl(true), reload); // refresh/reload + } + else + { + AddModuleMessage(Localizer["Success.Settings.SaveSite"], MessageType.Success); + } + } + } + else + { + AddModuleMessage(Localizer["Message.Aliases.Taken"], MessageType.Warning); + } + } + else + { + AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message); + AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error); + } + } + else + { + AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning); + } + } - private async Task DeleteSite() - { - try - { - var sites = await SiteService.GetSitesAsync(); - if (sites.Count > 1) - { - await SiteService.DeleteSiteAsync(PageState.Site.SiteId); - await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId); + private async Task DeleteSite() + { + try + { + var sites = await SiteService.GetSitesAsync(); + if (sites.Count > 1) + { + await SiteService.DeleteSiteAsync(PageState.Site.SiteId); + await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId); - var aliases = await AliasService.GetAliasesAsync(); - foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId)) - { - await AliasService.DeleteAliasAsync(a.AliasId); - } + var aliases = await AliasService.GetAliasesAsync(); + foreach (Alias a in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId)) + { + await AliasService.DeleteAliasAsync(a.AliasId); + } - NavigationManager.NavigateTo(NavigateUrl("admin/sites")); - } - else - { - AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning); - } - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message); - AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error); - } - } + NavigationManager.NavigateTo(NavigateUrl("admin/sites")); + } + else + { + AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning); + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message); + AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error); + } + } - private async Task SendEmail() - { - if (_smtphost != "" && _smtpport != "" && _smtpsender != "") - { - try - { - var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); - SettingService.SetSetting(settings, "SMTPHost", _smtphost); - SettingService.SetSetting(settings, "SMTPPort", _smtpport); - SettingService.SetSetting(settings, "SMTPSSL", _smtpssl); - SettingService.SetSetting(settings, "SMTPUsername", _smtpusername); - SettingService.SetSetting(settings, "SMTPPassword", _smtppassword); - SettingService.SetSetting(settings, "SMTPSender", _smtpsender); - await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); - await logger.LogInformation("Site SMTP Settings Saved"); + private async Task SendEmail() + { + if (_smtphost != "" && _smtpport != "" && _smtpsender != "") + { + try + { + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + SettingService.SetSetting(settings, "SMTPHost", _smtphost); + SettingService.SetSetting(settings, "SMTPPort", _smtpport); + SettingService.SetSetting(settings, "SMTPSSL", _smtpssl); + SettingService.SetSetting(settings, "SMTPUsername", _smtpusername); + SettingService.SetSetting(settings, "SMTPPassword", _smtppassword); + SettingService.SetSetting(settings, "SMTPSender", _smtpsender); + await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); + await logger.LogInformation("Site SMTP Settings Saved"); - await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly.")); - AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info); - } - catch (Exception ex) - { - await logger.LogError(ex, "Error Testing SMTP Configuration"); - AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error); - } - } - else - { - AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning); - } - } + await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User.DisplayName, PageState.User.Email, PageState.User.DisplayName, PageState.User.Email, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly.")); + AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Testing SMTP Configuration"); + AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error); + } + } + else + { + AddModuleMessage(Localizer["Message.required.Smtp"], MessageType.Warning); + } + } + + private async Task GetAliases() + { + _urls = string.Empty; + _defaultalias = string.Empty; + _aliases = await AliasService.GetAliasesAsync(); + foreach (Alias alias in _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).ToList()) + { + _urls += (_urls == string.Empty) ? alias.Name : ", " + alias.Name; + if (alias.IsDefault && string.IsNullOrEmpty(_defaultalias)) + { + _defaultalias = alias.Name; + } + } + } } diff --git a/Oqtane.Client/Modules/Admin/Sites/Add.razor b/Oqtane.Client/Modules/Admin/Sites/Add.razor index cdcef8da..7f807deb 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Add.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Add.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Modules.Admin.Sites @using Oqtane.Interfaces +@using System.Text.RegularExpressions @inherits ModuleBase @inject NavigationManager NavigationManager @inject ITenantService TenantService @@ -282,6 +283,7 @@ else { if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-") { + _urls = Regex.Replace(_urls, @"\r\n?|\n", ","); var duplicates = new List(); var aliases = await AliasService.GetAliasesAsync(); foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 09d7946d..69b891b7 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -43,7 +43,7 @@ else _sites = new List(); foreach (Alias alias in aliases) { - if (!_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId)) + if (alias.IsDefault && !_sites.Exists(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId)) { _sites.Add(alias); } @@ -52,16 +52,11 @@ else private void Edit(string name) { - if (name.Equals("*")) - { - var uri = new Uri(NavigationManager.Uri); - name = uri.Authority; - } - NavigationManager.NavigateTo(_scheme + name + "/admin/site/?reload"); + NavigationManager.NavigateTo(_scheme + name + "/admin/site", true); } private void Browse(string name) { - NavigationManager.NavigateTo(_scheme + name + "/?reload"); + NavigationManager.NavigateTo(_scheme + name, true); } } diff --git a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx index cefa464f..f757d453 100644 --- a/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx +++ b/Oqtane.Client/Resources/Modules/Admin/Site/Index.resx @@ -129,9 +129,6 @@ Default Container: - - Appearance - Default Admin Container @@ -223,7 +220,7 @@ Aliases: - Is Deleted? + Deleted? Logo: @@ -318,4 +315,13 @@ Delete Site + + The default alias for the site. Requests for non-default aliases will be redirected to the default alias. + + + Default Alias: + + + Aliases + \ No newline at end of file diff --git a/Oqtane.Client/Services/SettingService.cs b/Oqtane.Client/Services/SettingService.cs index e3449c05..f67d585d 100644 --- a/Oqtane.Client/Services/SettingService.cs +++ b/Oqtane.Client/Services/SettingService.cs @@ -152,7 +152,7 @@ namespace Oqtane.Services } else { - if (setting.SettingValue != kvp.Value) + if (setting.SettingValue != value || setting.IsPublic != ispublic) { setting.SettingValue = value; setting.IsPublic = ispublic; diff --git a/Oqtane.Server/Infrastructure/DatabaseManager.cs b/Oqtane.Server/Infrastructure/DatabaseManager.cs index fa5a9029..a4a94e61 100644 --- a/Oqtane.Server/Infrastructure/DatabaseManager.cs +++ b/Oqtane.Server/Infrastructure/DatabaseManager.cs @@ -367,7 +367,9 @@ namespace Oqtane.Infrastructure tenant = db.Tenant.FirstOrDefault(item => item.Name == install.TenantName); } - foreach (var aliasName in install.Aliases.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries)) + var aliasNames = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray(); + var firstAlias = aliasNames[0]; + foreach (var aliasName in aliasNames) { if (tenant != null) { @@ -376,6 +378,7 @@ namespace Oqtane.Infrastructure Name = aliasName, TenantId = tenant.TenantId, SiteId = -1, + IsDefault = (aliasName == firstAlias), CreatedBy = "", CreatedOn = DateTime.UtcNow, ModifiedBy = "", @@ -558,7 +561,8 @@ namespace Oqtane.Infrastructure { // set the alias explicitly so the tenant can be resolved var aliases = scope.ServiceProvider.GetRequiredService(); - var firstAlias = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)[0]; + var aliasNames = install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(sValue => sValue.Trim()).ToArray(); + var firstAlias = aliasNames[0]; var alias = aliases.GetAliases().FirstOrDefault(item => item.Name == firstAlias); var tenantManager = scope.ServiceProvider.GetRequiredService(); tenantManager.SetAlias(alias); @@ -650,7 +654,7 @@ namespace Oqtane.Infrastructure } } - foreach (var aliasName in install.Aliases.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) + foreach (var aliasName in aliasNames) { alias = aliases.GetAliases().FirstOrDefault(item => item.Name == aliasName); if (alias != null) diff --git a/Oqtane.Server/Migrations/Master/03000201_AddAliasRedirect.cs b/Oqtane.Server/Migrations/Master/03000201_AddAliasRedirect.cs new file mode 100644 index 00000000..bc5372b0 --- /dev/null +++ b/Oqtane.Server/Migrations/Master/03000201_AddAliasRedirect.cs @@ -0,0 +1,31 @@ +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.03.00.02.01")] + public class AddAliasRedirect : MultiDatabaseMigration + { + public AddAliasRedirect(IDatabase database) : base(database) + { + } + + protected override void Up(MigrationBuilder migrationBuilder) + { + //Add Column to Alias table + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); + aliasEntityBuilder.AddBooleanColumn("IsDefault", true); + aliasEntityBuilder.UpdateColumn("IsDefault", "1", "bool", ""); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + var aliasEntityBuilder = new AliasEntityBuilder(migrationBuilder, ActiveDatabase); + aliasEntityBuilder.DropColumn("IsDefault"); + } + } +} diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index 8a89763b..416f1cf6 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -18,6 +18,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Net.Http.Headers; using Microsoft.AspNetCore.Http; using System.Security.Claims; +using System.Net; namespace Oqtane.Pages { @@ -32,8 +33,9 @@ namespace Oqtane.Pages private readonly IPageRepository _pages; private readonly IUrlMappingRepository _urlMappings; private readonly IVisitorRepository _visitors; + private readonly IAliasRepository _aliases; - public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors) + public HostModel(IConfiguration configuration, ITenantManager tenantManager, ILocalizationManager localizationManager, ILanguageRepository languages, IAntiforgery antiforgery, ISiteRepository sites, IPageRepository pages, IUrlMappingRepository urlMappings, IVisitorRepository visitors, IAliasRepository aliases) { _configuration = configuration; _tenantManager = tenantManager; @@ -44,6 +46,7 @@ namespace Oqtane.Pages _pages = pages; _urlMappings = urlMappings; _visitors = visitors; + _aliases = aliases; } public string AntiForgeryToken = ""; @@ -77,11 +80,25 @@ namespace Oqtane.Pages var alias = _tenantManager.GetAlias(); if (alias != null) { - Route route = new Route(HttpContext.Request.GetEncodedUrl(), alias.Path); + var url = WebUtility.UrlDecode(HttpContext.Request.GetEncodedUrl()); + + // redirect non-default alias + if (!alias.IsDefault) + { + var redirect = _aliases.GetAliases() + .Where(item => item.TenantId == alias.TenantId && item.SiteId == alias.SiteId && item.IsDefault) + .FirstOrDefault(); + if (redirect != null) + { + return RedirectPermanent(url.Replace(alias.Name, redirect.Name)); + } + } var site = _sites.GetSite(alias.SiteId); if (site != null) { + Route route = new Route(url, alias.Path); + if (!string.IsNullOrEmpty(site.Runtime)) { Runtime = site.Runtime; @@ -128,7 +145,7 @@ namespace Oqtane.Pages else { // page does not exist - var url = route.SiteUrl + "/" + route.PagePath; + url = route.SiteUrl + "/" + route.PagePath; var urlMapping = _urlMappings.GetUrlMapping(site.SiteId, url); if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl)) { diff --git a/Oqtane.Server/Repository/AliasRepository.cs b/Oqtane.Server/Repository/AliasRepository.cs index 9e4e82d9..b7aa8b9a 100644 --- a/Oqtane.Server/Repository/AliasRepository.cs +++ b/Oqtane.Server/Repository/AliasRepository.cs @@ -4,6 +4,7 @@ using System.Linq; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Caching.Memory; using Oqtane.Models; +using Oqtane.Shared; namespace Oqtane.Repository { @@ -72,7 +73,7 @@ namespace Oqtane.Repository int start = segments.Length; for (int i = 0; i < segments.Length; i++) { - if (segments[i] == "api" || segments[i] == "pages" || segments[i] == "*") + if (segments[i] == "api" || segments[i] == "pages" || segments[i] == Constants.ModuleDelimiter) { start = i; break; @@ -89,8 +90,18 @@ namespace Oqtane.Repository } } - // return fallback alias if none found - return alias ?? aliases.Find(item => item.Name.Equals("*")); + // auto register alias if there is only a single tenant/site + if (alias == null && aliases.Select(item => new { item.TenantId, item.SiteId }).Distinct().Count() == 1) + { + alias = new Alias(); + alias.TenantId = aliases.First().TenantId; + alias.SiteId = aliases.First().SiteId; + alias.Name = url; + alias.IsDefault = false; + alias = AddAlias(alias); + } + + return alias; } public void DeleteAlias(int aliasId) diff --git a/Oqtane.Shared/Models/Alias.cs b/Oqtane.Shared/Models/Alias.cs index 0afad7d2..229fde44 100644 --- a/Oqtane.Shared/Models/Alias.cs +++ b/Oqtane.Shared/Models/Alias.cs @@ -30,6 +30,11 @@ namespace Oqtane.Models /// public int SiteId { get; set; } + /// + /// Specifies if the alias is the default for the tenant/site. Requests for non-default aliases are redirected to the default alias. + /// + public bool IsDefault { get; set; } + /// public string CreatedBy { get; set; } @@ -62,5 +67,6 @@ namespace Oqtane.Models } } } + } } diff --git a/Oqtane.Shared/Models/Route.cs b/Oqtane.Shared/Models/Route.cs index a41d4f46..bff8f17f 100644 --- a/Oqtane.Shared/Models/Route.cs +++ b/Oqtane.Shared/Models/Route.cs @@ -30,7 +30,7 @@ namespace Oqtane.Models Action = ""; UrlParameters = ""; - if (AliasPath.Length != 0) + if (AliasPath.Length != 0 && PagePath.StartsWith("/" + AliasPath)) { PagePath = PagePath.Substring(AliasPath.Length + 1); }