Merge pull request #1337 from sbwalker/dev

optimizing tenant resolution and routing
This commit is contained in:
Shaun Walker
2021-05-11 08:37:44 -04:00
committed by GitHub
85 changed files with 592 additions and 723 deletions

View File

@ -157,7 +157,7 @@
LoadDatabaseConfigComponent();
}
catch (Exception exception)
catch
{
_message = Localizer["Error loading Database Configuration Control"];
}

View File

@ -115,7 +115,9 @@
// complete the login on the server so that the cookies are set correctly on SignalR
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, username = _username, password = _password, remember = _remember, returnurl = _returnUrl };
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/login/", fields);
string url = "/pages/login/";
if (!string.IsNullOrEmpty(PageState.Alias.Path)) url = "/" + PageState.Alias.Path + url;
await interop.SubmitForm(url, fields);
}
else
{

View File

@ -30,7 +30,7 @@
</tr>
<tr>
<td>
<Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
<Label For="alias" HelpText="Enter 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 can be separated by commas." ResourceKey="Aliases">Aliases: </Label>
</td>
<td>
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
@ -60,67 +60,67 @@
</tr>
</table>
<Section Name="Appearance" Heading="Appearance" ResourceKey="Appearance">
<table class="table table-borderless">
<tr>
<td>
<Label For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
</td>
<td>
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
</td>
<td>
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
</td>
<td>
<select id="defaultTheme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;@Localizer["Select Theme"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
</td>
<td>
<select id="defaultAdminContainer" class="form-control" @bind="@_admincontainertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
<option value="">&lt;@Localizer["Default Admin Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
</table>
<table class="table table-borderless">
<tr>
<td>
<Label For="logo" HelpText="Specify a logo for the site" ResourceKey="Logo">Logo: </Label>
</td>
<td>
<FileManager FileId="@_logofileid" Filter="@Constants.ImageFiles" @ref="_logofilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="favicon" HelpText="Specify a Favicon" ResourceKey="FavoriteIcon">Favicon: </Label>
</td>
<td>
<FileManager FileId="@_faviconfileid" Filter="ico" @ref="_faviconfilemanager" />
</td>
</tr>
<tr>
<td>
<Label For="defaultTheme" HelpText="Select the sites default theme" ResourceKey="DefaultTheme">Default Theme: </Label>
</td>
<td>
<select id="defaultTheme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;@Localizer["Select Theme"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
</td>
<td>
<select id="defaultAdminContainer" class="form-control" @bind="@_admincontainertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
<option value="">&lt;@Localizer["Default Admin Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
</table>
</Section>
<Section Name="SMTP" Heading="SMTP Settings" ResourceKey="SMTPSettings">
<table class="table table-borderless">
@ -218,6 +218,7 @@
<br />
<button type="button" class="btn btn-success" @onclick="SaveSite">@Localizer["Save"]</button>
<ActionDialog Header="Delete Site" Message="@Localizer["Are You Sure You Wish To Delete This Site?"]" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteSite())" ResourceKey="DeleteSite" />
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
@ -276,7 +277,7 @@
_tenant = _tenantList.Find(item => item.TenantId == site.TenantId).Name;
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
_urls += alias.Name + "\n";
_urls += alias.Name + ",";
}
if (site.LogoFileId != null)
{
@ -424,7 +425,6 @@
site = await SiteService.UpdateSiteAsync(site);
_urls = _urls.Replace("\n", ",");
var names = _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
@ -476,6 +476,36 @@
}
}
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))
{
await AliasService.DeleteAliasAsync(a.AliasId);
}
NavigationManager.NavigateTo(NavigateUrl("admin/sites"));
}
else
{
AddModuleMessage(Localizer["You Are Not Authorized To Delete The Site"], MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
AddModuleMessage(Localizer["Error Deleting Site"], MessageType.Error);
}
}
private async Task SendEmail()
{
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")

View File

@ -29,7 +29,7 @@ else
</tr>
<tr>
<td>
<Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
<Label For="alias" HelpText="Enter 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 can be separated by commas." ResourceKey="Aliases">Aliases: </Label>
</td>
<td>
<textarea id="alias" class="form-control" @bind="@_urls" rows="3"></textarea>
@ -243,7 +243,7 @@ else
LoadDatabaseConfigComponent();
}
catch (Exception exception)
catch
{
AddModuleMessage(Localizer["Error loading Database Configuration Control"], MessageType.Error);
}
@ -373,7 +373,7 @@ else
if (!string.IsNullOrEmpty(config.TenantName))
{
config.SiteName = _name;
config.Aliases = _urls.Replace("\n", ",");
config.Aliases = _urls;
config.DefaultTheme = _themetype;
config.DefaultContainer = _containertype;
config.DefaultAdminContainer = _admincontainertype;

View File

@ -1,283 +0,0 @@
@namespace Oqtane.Modules.Admin.Sites
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject ISiteService SiteService
@inject ITenantService TenantService
@inject IAliasService AliasService
@inject IThemeService ThemeService
@inject IStringLocalizer<Edit> Localizer
@if (_initialized)
{
<table class="table table-borderless">
<tr>
<td>
<Label For="name" HelpText="Enter the name of the site" ResourceKey="Name">Name: </Label>
</td>
<td>
<input id="name" class="form-control" @bind="@_name" />
</td>
</tr>
<tr>
<td>
<Label For="alias" HelpText="Enter the alias for the server" ResourceKey="Aliases">Aliases: </Label>
</td>
<td>
<textarea id="alias" class="form-control" @bind="@_urls" rows="3" />
</td>
</tr>
<tr>
<td>
<Label For="defaultTheme" HelpText="Select the default theme for the website" ResourceKey="DefaultTheme">Default Theme: </Label>
</td>
<td>
<select id="defaultTheme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;@Localizer["Select Theme"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
</td>
<td>
<select id="defaultIdea" class="form-control" @bind="@_containertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="defaultAdminContainer" HelpText="Select the default admin container for the site" ResourceKey="DefaultAdminContainer">Default Admin Container: </Label>
</td>
<td>
<select id="defaultAdminContainer" class="form-control" @bind="@_admincontainertype">
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
<option value="">&lt;@Localizer["Default Admin Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="isDeleted" HelpText="Has this site been deleted?" ResourceKey="IsDeleted">Is Deleted? </Label>
</td>
<td>
<select id="isDeleted" class="form-control" @bind="@_isdeleted">
<option value="True">@Localizer["Yes"]</option>
<option value="False">@Localizer["No"]</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="tenant" HelpText="The tenant for the site" ResourceKey="Tenant">Tenant: </Label>
</td>
<td>
<input id="tenant" class="form-control" @bind="@_tenant" readonly />
</td>
</tr>
<tr>
<td>
<Label For="connectionstring" HelpText="The database connection string" ResourceKey="ConnectionString">Connection String: </Label>
</td>
<td>
<textarea id="connectionstring" class="form-control" @bind="@_connectionstring" rows="3" readonly></textarea>
</td>
</tr>
</table>
<br />
<button type="button" class="btn btn-success" @onclick="SaveSite">@Localizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@_createdby" CreatedOn="@_createdon" ModifiedBy="@_modifiedby" ModifiedOn="@_modifiedon" DeletedBy="@_deletedby" DeletedOn="@_deletedon"></AuditInfo>
}
@code {
private bool _initialized = false;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private Alias _alias;
private string _name = string.Empty;
private List<Alias> _aliasList;
private string _urls = string.Empty;
private string _themetype;
private string _containertype = "-";
private string _admincontainertype = "-";
private string _createdby;
private DateTime _createdon;
private string _modifiedby;
private DateTime _modifiedon;
private string _deletedby;
private DateTime? _deletedon;
private string _isdeleted;
private string _tenant = string.Empty;
private string _connectionstring = string.Empty;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
{
try
{
_themeList = await ThemeService.GetThemesAsync();
_aliasList = await AliasService.GetAliasesAsync();
_alias = _aliasList.Find(item => item.AliasId == Int32.Parse(PageState.QueryString["id"]));
SiteService.SetAlias(_alias);
var site = await SiteService.GetSiteAsync(_alias.SiteId);
if (site != null)
{
_name = site.Name;
foreach (Alias alias in _aliasList.Where(item => item.SiteId == site.SiteId && item.TenantId == site.TenantId).ToList())
{
_urls += alias.Name + "\n";
}
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = site.DefaultThemeType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = site.DefaultContainerType;
_admincontainertype = site.AdminContainerType;
_createdby = site.CreatedBy;
_createdon = site.CreatedOn;
_modifiedby = site.ModifiedBy;
_modifiedon = site.ModifiedOn;
_deletedby = site.DeletedBy;
_deletedon = site.DeletedOn;
_isdeleted = site.IsDeleted.ToString();
List<Tenant> tenants = await TenantService.GetTenantsAsync();
Tenant tenant = tenants.Find(item => item.TenantId == site.TenantId);
if (tenant != null)
{
_tenant = tenant.Name;
_connectionstring = tenant.DBConnectionString;
}
_initialized = true;
}
}
catch (Exception ex)
{
await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Loading Site {SiteId} {Error}", _alias.SiteId, ex.Message);
AddModuleMessage(ex.Message, MessageType.Error);
}
}
private async void ThemeChanged(ChangeEventArgs e)
{
try
{
_themetype = (string)e.Value;
if (_themetype != "-")
{
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_containers = new List<ThemeControl>();
}
_containertype = "-";
_admincontainertype = "";
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
AddModuleMessage(Localizer["Error Loading Pane Layouts For Theme"], MessageType.Error);
}
}
private async Task SaveSite()
{
try
{
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
{
var unique = true;
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
if (_aliasList.Exists(item => item.Name == name && item.SiteId != _alias.SiteId && item.TenantId != _alias.TenantId))
{
unique = false;
}
}
if (unique)
{
SiteService.SetAlias(_alias);
var site = await SiteService.GetSiteAsync(_alias.SiteId);
if (site != null)
{
site.Name = _name;
site.LogoFileId = null;
site.DefaultThemeType = _themetype;
site.DefaultContainerType = _containertype;
site.AdminContainerType = _admincontainertype;
site.IsDeleted = (_isdeleted == null || Boolean.Parse(_isdeleted));
site = await SiteService.UpdateSiteAsync(site);
_urls = _urls.Replace("\n", ",");
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);
}
}
foreach (string name in names)
{
if (!_aliasList.Exists(item => item.Name == name))
{
Alias alias = new Alias
{
Name = name,
TenantId = site.TenantId,
SiteId = site.SiteId
};
await AliasService.AddAliasAsync(alias);
}
}
await Log(_alias, LogLevel.Information, PermissionNames.Edit, null, "Site Saved {Site}", site);
NavigationManager.NavigateTo(NavigateUrl());
}
}
else
{
AddModuleMessage(Localizer["An Alias Specified Has Already Been Used For Another Site"], MessageType.Warning);
}
}
else
{
AddModuleMessage(Localizer["You Must Provide A Site Name, Alias, And Default Theme/Container"], MessageType.Warning);
}
}
catch (Exception ex)
{
await Log(_alias, LogLevel.Error, string.Empty, ex, "Error Saving Site {SiteId} {Error}", _alias.SiteId, ex.Message);
AddModuleMessage(Localizer["Error Saving Site"], MessageType.Error);
}
}
}

View File

@ -15,13 +15,11 @@ else
<Pager Items="@_sites">
<Header>
<th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th>
<th>@Localizer["Name"]</th>
</Header>
<Row>
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.AliasId.ToString())" ResourceKey="EditSite" /></td>
<td><ActionDialog Header="Delete Site" Message="@Localizer["Are You Sure You Wish To Delete The {0} Site?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteSite(context))" ResourceKey="DeleteSite" /></td>
<td><NavLink class="btn btn-primary" href="@(_scheme + context.Name +"/admin/site")">@Localizer["Edit"]</NavLink></td>
<td><a href="@(_scheme + context.Name +"?reload")">@context.Name</a></td>
</Row>
</Pager>
@ -48,34 +46,4 @@ else
}
}
}
private async Task DeleteSite(Alias alias)
{
try
{
if (alias.SiteId != PageState.Site.SiteId || alias.TenantId != PageState.Site.TenantId)
{
SiteService.SetAlias(alias);
await SiteService.DeleteSiteAsync(alias.SiteId);
await Log(alias, LogLevel.Information, "", null, "Site Deleted {SiteId}", alias.SiteId);
var aliases = await AliasService.GetAliasesAsync();
foreach (Alias a in aliases.Where(item => item.SiteId == alias.SiteId && item.TenantId == alias.TenantId))
{
await AliasService.DeleteAliasAsync(a.AliasId);
}
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["You Can Not Delete The Current Site"], MessageType.Warning);
}
}
catch (Exception ex)
{
await Log(alias, LogLevel.Error, "", ex, "Error Deleting Site {SiteId} {Error}", alias.SiteId, ex.Message);
AddModuleMessage(Localizer["Error Deleting Site"], MessageType.Error);
}
}
}

View File

@ -51,7 +51,7 @@
if (htmltext != null)
{
_content = htmltext.Content;
_content = _content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl);
_content = _content.Replace(Constants.ContentUrl, "/" + PageState.Alias.Path + Constants.ContentUrl);
_createdby = htmltext.CreatedBy;
_createdon = htmltext.CreatedOn;
_modifiedby = htmltext.ModifiedBy;
@ -72,7 +72,7 @@
private async Task SaveContent()
{
string content = await RichTextEditorHtml.GetHtml();
content = content.Replace("/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl, Constants.ContentUrl);
content = content.Replace("/" + PageState.Alias.Path + Constants.ContentUrl, Constants.ContentUrl);
try
{

View File

@ -26,7 +26,7 @@
if (htmltext != null)
{
content = htmltext.Content;
content = content.Replace(Constants.ContentUrl, "/" + PageState.Alias.AliasId.ToString() + Constants.ContentUrl);
content = content.Replace(Constants.ContentUrl, "/" + PageState.Alias.Path + Constants.ContentUrl);
}
}
catch (Exception ex)

View File

@ -17,7 +17,7 @@ namespace Oqtane.Modules.HtmlText.Services
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, "HtmlText");
private string ApiUrl => CreateApiUrl("HtmlText", _siteState.Alias);
public async Task<Models.HtmlText> GetHtmlTextAsync(int moduleId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -19,7 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Alias");
private string Apiurl => CreateApiUrl("Alias", _siteState.Alias);
public async Task<List<Alias>> GetAliasesAsync()
{
@ -32,10 +32,9 @@ namespace Oqtane.Services
return await GetJsonAsync<Alias>($"{Apiurl}/{aliasId}");
}
public async Task<Alias> GetAliasAsync(string name, DateTime lastSyncDate)
public async Task<Alias> GetAliasAsync(string path, DateTime lastSyncDate)
{
name = (string.IsNullOrEmpty(name)) ? "~" : name;
return await GetJsonAsync<Alias>($"{Apiurl}/name/{WebUtility.UrlEncode(name)}?sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
return await GetJsonAsync<Alias>($"{Apiurl}/name/?path={WebUtility.UrlEncode(path)}&sync={lastSyncDate.ToString("yyyyMMddHHmmssfff")}");
}
public async Task<Alias> AddAliasAsync(Alias alias)

View File

@ -21,7 +21,7 @@ namespace Oqtane.Services
_jsRuntime = jsRuntime;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "File");
private string Apiurl => CreateApiUrl("File", _siteState.Alias);
public async Task<List<File>> GetFilesAsync(int folderId)
{

View File

@ -19,7 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, "Folder");
private string ApiUrl => CreateApiUrl("Folder", _siteState.Alias);
public async Task<List<Folder>> GetFoldersAsync(int siteId)
{

View File

@ -7,9 +7,14 @@ namespace Oqtane.Services
{
public class InstallationService : ServiceBase, IInstallationService
{
public InstallationService(HttpClient http):base(http) { }
private readonly SiteState _siteState;
private string ApiUrl => CreateApiUrl("Installation");
public InstallationService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl("Installation", _siteState.Alias);
public async Task<Installation> IsInstalled()
{

View File

@ -1,4 +1,5 @@
using Oqtane.Models;
using Oqtane.Models;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
@ -6,8 +7,6 @@ namespace Oqtane.Services
{
public interface ISiteService
{
void SetAlias(Alias alias);
Task<List<Site>> GetSitesAsync();
Task<Site> GetSiteAsync(int siteId);
@ -17,5 +16,8 @@ namespace Oqtane.Services
Task<Site> UpdateSiteAsync(Site site);
Task DeleteSiteAsync(int siteId);
[Obsolete("This method is deprecated.", false)]
void SetAlias(Alias alias);
}
}

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "JobLog");
private string Apiurl => CreateApiUrl("JobLog", _siteState.Alias);
public async Task<List<JobLog>> GetJobLogsAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Job");
private string Apiurl => CreateApiUrl("Job", _siteState.Alias);
public async Task<List<Job>> GetJobsAsync()
{

View File

@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Language");
private string Apiurl => CreateApiUrl("Language", _siteState.Alias);
public async Task<List<Language>> GetLanguagesAsync(int siteId)
{

View File

@ -15,7 +15,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Localization");
private string Apiurl => CreateApiUrl("Localization", _siteState.Alias);
public async Task<IEnumerable<Culture>> GetCulturesAsync() => await GetJsonAsync<IEnumerable<Culture>>(Apiurl);
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text.Json;
@ -23,7 +23,7 @@ namespace Oqtane.Services
_navigationManager = navigationManager;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Log");
private string Apiurl => CreateApiUrl("Log", _siteState.Alias);
public async Task<List<Log>> GetLogsAsync(int siteId, string level, string function, int rows)
{
@ -49,7 +49,6 @@ namespace Oqtane.Services
}
else
{
base.Alias = alias;
log.SiteId = alias.SiteId;
}
log.PageId = pageId;

View File

@ -21,7 +21,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "ModuleDefinition");
private string Apiurl => CreateApiUrl("ModuleDefinition", _siteState.Alias);
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Module");
private string Apiurl => CreateApiUrl("Module", _siteState.Alias);
public async Task<List<Module>> GetModulesAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using Oqtane.Shared;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Notification");
private string Apiurl => CreateApiUrl("Notification", _siteState.Alias);
public async Task<List<Notification>> GetNotificationsAsync(int siteId, string direction, int userId)
{

View File

@ -3,14 +3,19 @@ using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Linq;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class PackageService : ServiceBase, IPackageService
{
public PackageService(HttpClient http) : base(http) { }
{
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("Package");
public PackageService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("Package", _siteState.Alias);
public async Task<List<Package>> GetPackagesAsync(string tag)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Net.Http;
using System.Threading.Tasks;
using Oqtane.Shared;
@ -15,7 +15,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "PageModule");
private string Apiurl => CreateApiUrl("PageModule", _siteState.Alias);
public async Task<PageModule> GetPageModuleAsync(int pageModuleId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Linq;
using System.Net.Http;
@ -20,7 +20,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Page");
private string Apiurl => CreateApiUrl("Page", _siteState.Alias);
public async Task<List<Page>> GetPagesAsync(int siteId)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
@ -17,7 +17,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Profile");
private string Apiurl => CreateApiUrl("Profile", _siteState.Alias);
public async Task<List<Profile>> GetProfilesAsync(int siteId)
{

View File

@ -18,7 +18,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Role");
private string Apiurl => CreateApiUrl("Role", _siteState.Alias);
public async Task<List<Role>> GetRolesAsync(int siteId)
{

View File

@ -5,6 +5,7 @@ using System.Net.Http.Json;
using System.Threading;
using System.Threading.Tasks;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Services
{
@ -17,6 +18,55 @@ namespace Oqtane.Services
_http = client;
}
public string CreateApiUrl(string serviceName, Alias alias)
{
return CreateApiUrl(serviceName, alias, ControllerRoutes.ApiRoute);
}
public string CreateApiUrl(string serviceName, Alias alias, string routeTemplate)
{
string apiurl = "/";
if (routeTemplate == ControllerRoutes.ApiRoute)
{
if (alias != null && !string.IsNullOrEmpty(alias.Path))
{
// include the alias path for multi-tenant context
apiurl += alias.Path + "/";
}
}
else
{
// legacy support for ControllerRoutes.Default
if (alias != null)
{
// include the alias for multi-tenant context
apiurl += $"{alias.AliasId}/";
}
else
{
// tenant agnostic
apiurl += "~/";
}
}
apiurl += $"api/{serviceName}";
return apiurl;
}
// add entityid parameter to url for custom authorization policy
public string CreateAuthorizationPolicyUrl(string url, int entityId)
{
string qs = "entityid=" + entityId.ToString();
if (url.Contains("?"))
{
return url + "&" + qs;
}
else
{
return url + "?" + qs;
}
}
protected async Task GetAsync(string uri)
{
var response = await _http.GetAsync(uri);
@ -135,61 +185,26 @@ namespace Oqtane.Services
//TODO Missing content JSON validation
}
// create an API Url which is tenant agnostic ( for use during installation )
public string CreateApiUrl(string serviceName)
{
return CreateApiUrl(null, serviceName);
}
// create an API Url which is tenant aware ( for use with repositories )
public string CreateApiUrl(Alias alias, string serviceName)
{
string apiurl = "/";
if (Alias != null)
{
alias = Alias; // override the default alias ( for cross-tenant service calls )
}
if (alias != null)
{
// include the alias for multi-tenant context
apiurl += $"{alias.AliasId}/";
}
else
{
// tenant agnostic
apiurl += "~/";
}
apiurl += $"api/{serviceName}";
return apiurl;
}
// can be used to override the default alias
public Alias Alias { get; set; }
// add entityid parameter to url for custom authorization policy
public string CreateAuthorizationPolicyUrl(string url, int entityId)
{
string qs = "entityid=" + entityId.ToString();
if (url.Contains("?"))
{
return url + "&" + qs;
}
else
{
return url + "?" + qs;
}
}
[Obsolete("This method is obsolete. Use CreateApiUrl(Alias alias, string serviceName) instead.", false)]
public string CreateApiUrl(Alias alias, string absoluteUri, string serviceName)
{
// only retained for short term backward compatibility
return CreateApiUrl(alias, serviceName);
}
[Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)]
public string CreateApiUrl(string serviceName)
{
return CreateApiUrl(serviceName, null, ControllerRoutes.Default);
}
[Obsolete("This method is deprecated.", false)]
public Alias Alias { get; set; }
[Obsolete("This method is obsolete. Use CreateApiUrl(string serviceName, Alias alias) instead.", false)]
public string CreateApiUrl(Alias alias, string serviceName)
{
return CreateApiUrl(serviceName, alias, ControllerRoutes.Default);
}
}
}

View File

@ -1,4 +1,4 @@
using System;
using System;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
@ -18,7 +18,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Setting");
private string Apiurl => CreateApiUrl("Setting", _siteState.Alias);
public async Task<Dictionary<string, string>> GetTenantSettingsAsync()
{
return await GetSettingsAsync(EntityNames.Tenant, -1);

View File

@ -1,9 +1,10 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using System.Collections.Generic;
using Oqtane.Shared;
using System;
namespace Oqtane.Services
{
@ -18,12 +19,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Site");
public void SetAlias(Alias alias)
{
base.Alias = alias;
}
private string Apiurl => CreateApiUrl("Site", _siteState.Alias);
public async Task<List<Site>> GetSitesAsync()
{
@ -50,5 +46,11 @@ namespace Oqtane.Services
{
await DeleteAsync($"{Apiurl}/{siteId}");
}
[Obsolete("This method is deprecated.", false)]
public void SetAlias(Alias alias)
{
base.Alias = alias;
}
}
}

View File

@ -1,4 +1,5 @@
using Oqtane.Models;
using Oqtane.Models;
using Oqtane.Shared;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
@ -8,9 +9,13 @@ namespace Oqtane.Services
{
public class SiteTemplateService : ServiceBase, ISiteTemplateService
{
public SiteTemplateService(HttpClient http) : base(http) { }
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("SiteTemplate");
public SiteTemplateService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("SiteTemplate", _siteState.Alias);
public async Task<List<SiteTemplate>> GetSiteTemplatesAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using Oqtane.Shared;
using System.Net.Http;
using System.Threading.Tasks;
@ -14,7 +14,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Sql");
private string Apiurl => CreateApiUrl("Sql", _siteState.Alias);
public async Task<SqlQuery> ExecuteQueryAsync(SqlQuery sqlquery)
{

View File

@ -1,14 +1,20 @@
using System.Net.Http;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class SystemService : ServiceBase, ISystemService
{
public SystemService(HttpClient http) : base(http) { }
private readonly SiteState _siteState;
private string Apiurl => CreateApiUrl("System");
public SystemService(HttpClient http, SiteState siteState) : base(http)
{
_siteState = siteState;
}
private string Apiurl => CreateApiUrl("System", _siteState.Alias);
public async Task<Dictionary<string, string>> GetSystemInfoAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Net.Http;
using System.Threading.Tasks;
using System.Collections.Generic;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "Tenant");
private string Apiurl => CreateApiUrl("Tenant", _siteState.Alias);
public async Task<List<Tenant>> GetTenantsAsync()
{

View File

@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string ApiUrl => CreateApiUrl(_siteState.Alias, "Theme");
private string ApiUrl => CreateApiUrl("Theme", _siteState.Alias);
public async Task<List<Theme>> GetThemesAsync()
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
@ -16,7 +16,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "UserRole");
private string Apiurl => CreateApiUrl("UserRole", _siteState.Alias);
public async Task<List<UserRole>> GetUserRolesAsync(int siteId)
{

View File

@ -14,7 +14,7 @@ namespace Oqtane.Services
_siteState = siteState;
}
private string Apiurl => CreateApiUrl(_siteState.Alias, "User");
private string Apiurl => CreateApiUrl("User", _siteState.Alias);
public async Task<User> GetUserAsync(int userId, int siteId)
{

View File

@ -39,7 +39,9 @@ namespace Oqtane.Themes.Controls
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = !authorizedtoviewpage ? PageState.Alias.Path : PageState.Alias.Path + "/" + PageState.Page.Path };
await interop.SubmitForm($"/{PageState.Alias.AliasId}/pages/logout/", fields);
string url = "/pages/logout/";
if (!string.IsNullOrEmpty(PageState.Alias.Path)) url = "/" + PageState.Alias.Path + url;
await interop.SubmitForm(url, fields);
}
else
{