added support for default alias specification, alias auto registration, alias redirect, alias line break delimiters

This commit is contained in:
Shaun Walker
2021-12-22 15:43:59 -05:00
parent 22c2d56da0
commit c21a097fd2
11 changed files with 329 additions and 227 deletions

View File

@ -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 @@
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
<div class="col-sm-9">
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
}
else
{
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" readonly></textarea>
}
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
<div class="col-sm-9">
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
<div class="col-sm-9">
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
<option value="-">&lt;@Localizer["Theme.Select"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</div>
</div>
</div>
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
<div class="col-sm-9">
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
<div class="col-sm-9">
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
<div class="col-sm-9">
<select id="defaultTheme" class="form-select" value="@_themetype" @onchange="(e => ThemeChanged(e))" required>
<option value="-">&lt;@Localizer["Theme.Select"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
<div class="col-sm-9">
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
<option value="-">&lt;@Localizer["Container.Select"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
<div class="col-sm-9">
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
<option value="-">&lt;@Localizer["Container.Select"]&gt;</option>
<option value="@Constants.DefaultAdminContainer">&lt;@Localizer["DefaultAdminContainer"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
<div class="col-sm-9">
<select id="defaultContainer" class="form-select" @bind="@_containertype" required>
<option value="-">&lt;@Localizer["Container.Select"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
</Section>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
<div class="col-sm-9">
<select id="defaultAdminContainer" class="form-select" @bind="@_admincontainertype" required>
<option value="-">&lt;@Localizer["Container.Select"]&gt;</option>
<option value="@Constants.DefaultAdminContainer">&lt;@Localizer["DefaultAdminContainer"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isDeleted" HelpText="Is this site deleted?" ResourceKey="IsDeleted">Deleted? </Label>
<div class="col-sm-9">
<select id="isDeleted" class="form-select" @bind="@_isdeleted" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
<div class="container">
<div class="row mb-1 align-items-center">
@ -176,6 +160,27 @@
</Section>
@if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
{
<Section Name="Aliases" Heading="Aliases" ResourceKey="Aliases">
<div class="container">
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="alias" HelpText="The aliases for the site. An alias can be a domain name (www.site.com) or a virtual folder (ie. www.site.com/folder). If a site has multiple aliases they should be separated by commas." ResourceKey="Aliases">Aliases: </Label>
<div class="col-sm-9">
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" required></textarea>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="defaultalias" HelpText="The default alias for the site. Requests for non-default aliases will be redirected to the default alias." ResourceKey="DefaultAlias">Default Alias: </Label>
<div class="col-sm-9">
<select id="defaultalias" class="form-select" @bind="@_defaultalias" required>
@foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
<option value="@name">@name</option>
}
</select>
</div>
</div>
</div>
</Section>
<Section Name="Hosting" Heading="Hosting Model" ResourceKey="Hosting">
<div class="container">
<div class="row mb-1 align-items-center">
@ -238,7 +243,8 @@
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _name = string.Empty;
private List<Alias> _aliasList;
private List<Alias> _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;
}
}
}
}

View File

@ -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<string>();
var aliases = await AliasService.GetAliasesAsync();
foreach (string name in _urls.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries))

View File

@ -43,7 +43,7 @@ else
_sites = new List<Alias>();
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);
}
}

View File

@ -129,9 +129,6 @@
<data name="DefaultContainer.Text" xml:space="preserve">
<value>Default Container: </value>
</data>
<data name="Appearance.Heading" xml:space="preserve">
<value>Appearance</value>
</data>
<data name="DefaultAdminContainer" xml:space="preserve">
<value>Default Admin Container</value>
</data>
@ -223,7 +220,7 @@
<value>Aliases: </value>
</data>
<data name="IsDeleted.Text" xml:space="preserve">
<value>Is Deleted? </value>
<value>Deleted? </value>
</data>
<data name="Logo.Text" xml:space="preserve">
<value>Logo: </value>
@ -318,4 +315,13 @@
<data name="DeleteSite.Text" xml:space="preserve">
<value>Delete Site</value>
</data>
<data name="DefaultAlias.HelpText" xml:space="preserve">
<value>The default alias for the site. Requests for non-default aliases will be redirected to the default alias.</value>
</data>
<data name="DefaultAlias.Text" xml:space="preserve">
<value>Default Alias: </value>
</data>
<data name="Aliases.Heading" xml:space="preserve">
<value>Aliases</value>
</data>
</root>

View File

@ -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;

View File

@ -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<IAliasRepository>();
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<ITenantManager>();
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)

View File

@ -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");
}
}
}

View File

@ -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))
{

View File

@ -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)

View File

@ -30,6 +30,11 @@ namespace Oqtane.Models
/// </summary>
public int SiteId { get; set; }
/// <summary>
/// Specifies if the alias is the default for the tenant/site. Requests for non-default aliases are redirected to the default alias.
/// </summary>
public bool IsDefault { get; set; }
/// <inheritdoc />
public string CreatedBy { get; set; }
@ -62,5 +67,6 @@ namespace Oqtane.Models
}
}
}
}
}

View File

@ -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);
}