Performance improvements, refactoring of multi-tenant support, split Alias and Tenant entities for cleaner separation of concerns, create an additional site during installation for demonstratng multitenancy

This commit is contained in:
Shaun Walker 2019-05-24 13:33:19 -04:00
parent 0067521cd5
commit 8deb119f36
57 changed files with 880 additions and 309 deletions

View File

@ -12,7 +12,7 @@
{
if (p.IsNavigation && UserService.IsAuthorized(PageState.User, p.ViewPermissions))
{
string url = PageState.Alias + p.Path;
string url = NavigateUrl(p.Path);
<li class="list-group-item">
<NavLink class="nav-link" href="@url" Match="NavLinkMatch.All">
<span class="oi @p.Icon" aria-hidden="true"></span> @p.Name

View File

@ -39,7 +39,7 @@
{
var interop = new Interop(jsRuntime);
await interop.SetCookie("user", user.UserId.ToString(), 7);
UriHelper.NavigateTo(PageState.Alias, true);
UriHelper.NavigateTo(NavigateUrl(""), true);
}
else
{

View File

@ -3,7 +3,6 @@
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Client.Modules.Controls
@inherits ModuleBase
@inject IUriHelper UriHelper
@inject IPageService PageService
@ -132,11 +131,10 @@
string viewpermissions = "All Users";
string editpermissions = "Administrators";
protected override async Task OnInitAsync()
protected override void OnInit()
{
var Themes = await ThemeService.GetThemesAsync();
themes = ThemeService.GetThemeTypes(Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(Themes);
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
}
private async Task SavePage()

View File

@ -3,7 +3,6 @@
@using Oqtane.Services
@using Oqtane.Modules
@using Oqtane.Shared
@using Oqtane.Client.Modules.Controls
@inherits ModuleBase
@inject IUriHelper UriHelper
@inject IPageService PageService
@ -133,11 +132,10 @@
string viewpermissions;
string editpermissions;
protected override async Task OnInitAsync()
protected override void OnInit()
{
List<Theme> Themes = await ThemeService.GetThemesAsync();
themes = ThemeService.GetThemeTypes(Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(Themes);
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
PageId = Int32.Parse(PageState.QueryString["id"]);
Page p = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();
@ -159,6 +157,6 @@
private async Task DeletePage()
{
await PageService.DeletePageAsync(Int32.Parse(PageState.QueryString["id"]));
UriHelper.NavigateTo(PageState.Alias);
UriHelper.NavigateTo(NavigateUrl("", true));
}
}

View File

@ -133,11 +133,10 @@
string viewpermissions;
string editpermissions;
protected override async Task OnInitAsync()
protected override void OnInit()
{
List<Theme> Themes = await ThemeService.GetThemesAsync();
themes = ThemeService.GetThemeTypes(Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(Themes);
themes = ThemeService.GetThemeTypes(PageState.Themes);
panelayouts = ThemeService.GetPaneLayoutTypes(PageState.Themes);
PageId = Int32.Parse(PageState.QueryString["id"]);
Page p = PageState.Pages.Where(item => item.PageId == PageId).FirstOrDefault();

View File

@ -3,10 +3,11 @@
@using Oqtane.Client.Modules.HtmlText.Services
@using Oqtane.Shared.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Client.Modules.Controls
@using Oqtane.Shared;
@inherits ModuleBase
@inject IUriHelper UriHelper
@inject HttpClient http
@inject SiteState sitestate
<form>
<table class="form-group">
@ -32,7 +33,7 @@
protected override async Task OnInitAsync()
{
HtmlTextService htmltextservice = new HtmlTextService(http, UriHelper);
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate);
List<HtmlTextInfo> htmltextlist = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltextlist != null)
{
@ -43,7 +44,7 @@
private async Task SaveContent()
{
HtmlTextService htmltextservice = new HtmlTextService(http, UriHelper);
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate);
if (htmltext != null)
{
htmltext.Content = content;

View File

@ -3,9 +3,10 @@
@using Oqtane.Shared.Modules.HtmlText.Models
@using System.Net.Http;
@using Oqtane.Client.Modules.Controls
@using Oqtane.Shared;
@inherits ModuleBase
@inject HttpClient http
@inject IUriHelper UriHelper
@inject SiteState sitestate
@((MarkupString)content)
@ -16,7 +17,7 @@
protected override async Task OnInitAsync()
{
HtmlTextService htmltextservice = new HtmlTextService(http, UriHelper);
HtmlTextService htmltextservice = new HtmlTextService(http, sitestate);
List<HtmlTextInfo> htmltext = await htmltextservice.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{

View File

@ -5,18 +5,24 @@ using System.Net.Http;
using Microsoft.AspNetCore.Components;
using Oqtane.Services;
using Oqtane.Shared.Modules.HtmlText.Models;
using Oqtane.Shared;
namespace Oqtane.Client.Modules.HtmlText.Services
{
public class HtmlTextService : ServiceBase, IHtmlTextService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public HtmlTextService(HttpClient http, IUriHelper urihelper)
public HtmlTextService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "HtmlText");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "HtmlText"); }
}
public async Task<List<HtmlTextInfo>> GetHtmlTextAsync(int ModuleId)

View File

@ -20,46 +20,32 @@ namespace Oqtane.Modules
public string NavigateUrl()
{
return NavigateUrl(PageState.Page.Path, false);
return Utilities.NavigateUrl(PageState);
}
public string NavigateUrl(bool reload)
{
return NavigateUrl(PageState.Page.Path, reload);
return Utilities.NavigateUrl(PageState, reload);
}
public string NavigateUrl(string path)
{
return NavigateUrl(path, false);
return Utilities.NavigateUrl(PageState, path);
}
public string NavigateUrl(string path, bool reload)
{
string url = PageState.Alias + path;
if (reload)
{
url += "?reload=true";
}
return url;
return Utilities.NavigateUrl(PageState, path, reload);
}
public string EditUrl(string action)
{
return EditUrl(action, "");
return Utilities.EditUrl(PageState, ModuleState, action, "");
}
public string EditUrl(string action, string parameters)
{
string url = PageState.Alias + PageState.Page.Path + "?mid=" + ModuleState.ModuleId.ToString();
if (action != "")
{
url += "&ctl=" + action;
}
if (!string.IsNullOrEmpty(parameters))
{
url += "&" + parameters;
}
return url;
return Utilities.EditUrl(PageState, ModuleState, action, parameters);
}
}
}

View File

@ -0,0 +1,53 @@
using Oqtane.Models;
using System.Threading.Tasks;
using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class AliasService : ServiceBase, IAliasService
{
private readonly HttpClient http;
private readonly IUriHelper urihelper;
public AliasService(HttpClient http, IUriHelper urihelper)
{
this.http = http;
this.urihelper = urihelper;
}
private string apiurl
{
get { return CreateApiUrl(urihelper.GetAbsoluteUri(), "Alias"); }
}
public async Task<List<Alias>> GetAliasesAsync()
{
List<Alias> aliases = await http.GetJsonAsync<List<Alias>>(apiurl);
return aliases.OrderBy(item => item.Name).ToList();
}
public async Task<Alias> GetAliasAsync(int AliasId)
{
List<Alias> aliases = await http.GetJsonAsync<List<Alias>>(apiurl);
return aliases.Where(item => item.AliasId == AliasId).FirstOrDefault();
}
public async Task AddAliasAsync(Alias alias)
{
await http.PostJsonAsync(apiurl, alias);
}
public async Task UpdateAliasAsync(Alias alias)
{
await http.PutJsonAsync(apiurl + "/" + alias.AliasId.ToString(), alias);
}
public async Task DeleteAliasAsync(int AliasId)
{
await http.DeleteAsync(apiurl + "/" + AliasId.ToString());
}
}
}

View File

@ -0,0 +1,19 @@
using Oqtane.Models;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Oqtane.Services
{
public interface IAliasService
{
Task<List<Alias>> GetAliasesAsync();
Task<Alias> GetAliasAsync(int AliasId);
Task AddAliasAsync(Alias alias);
Task UpdateAliasAsync(Alias alias);
Task DeleteAliasAsync(int AliasId);
}
}

View File

@ -6,54 +6,56 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using System;
using System.Reflection;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class ModuleDefinitionService : ServiceBase, IModuleDefinitionService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
private List<ModuleDefinition> moduledefinitions;
public ModuleDefinitionService(HttpClient http, IUriHelper urihelper)
public ModuleDefinitionService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "ModuleDefinition");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "ModuleDefinition"); }
}
public async Task<List<ModuleDefinition>> GetModuleDefinitionsAsync()
{
if (moduledefinitions == null)
List<ModuleDefinition> moduledefinitions = await http.GetJsonAsync<List<ModuleDefinition>>(apiurl);
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (ModuleDefinition moduledefinition in moduledefinitions)
{
moduledefinitions = await http.GetJsonAsync<List<ModuleDefinition>>(apiurl);
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (ModuleDefinition moduledefinition in moduledefinitions)
if (moduledefinition.Dependencies != "")
{
if (moduledefinition.Dependencies != "")
foreach (string dependency in moduledefinition.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
foreach (string dependency in moduledefinition.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
string assemblyname = dependency.Replace(".dll", "");
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
string assemblyname = dependency.Replace(".dll", "");
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
}
if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + moduledefinition.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
if (assemblies.Where(item => item.FullName.StartsWith(moduledefinition.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + moduledefinition.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
return moduledefinitions.OrderBy(item => item.Name).ToList();
}
}

View File

@ -4,18 +4,24 @@ using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class ModuleService : ServiceBase, IModuleService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public ModuleService(HttpClient http, IUriHelper urihelper)
public ModuleService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "Module");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "Module"); }
}
public async Task<List<Module>> GetModulesAsync(int PageId)

View File

@ -4,18 +4,24 @@ using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class PageModuleService : ServiceBase, IPageModuleService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public PageModuleService(HttpClient http, IUriHelper urihelper)
public PageModuleService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "PageModule");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "PageModule"); }
}
public async Task<List<PageModule>> GetPageModulesAsync()

View File

@ -4,18 +4,24 @@ using System.Linq;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class PageService : ServiceBase, IPageService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public PageService(HttpClient http, IUriHelper urihelper)
public PageService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "Page");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "Page"); }
}
public async Task<List<Page>> GetPagesAsync(int SiteId)

View File

@ -1,20 +1,24 @@
using System;
using Oqtane.Models;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class ServiceBase
{
// method for alias agnostic api call
public string CreateApiUrl(string absoluteUri, string serviceName)
{
Uri uri = new Uri(absoluteUri);
string apiurl = uri.Scheme + "://" + uri.Authority + "/";
string alias = Utilities.GetAlias(absoluteUri);
if (alias != "")
{
apiurl += alias;
}
else
string apiurl = uri.Scheme + "://" + uri.Authority + "/~/api/" + serviceName;
return apiurl;
}
// method for alias specific api call
public string CreateApiUrl(Alias alias, string serviceName)
{
string apiurl = alias.Url + "/";
if (alias.Path == "")
{
apiurl += "~/";
}

View File

@ -4,18 +4,24 @@ using System.Net.Http;
using System.Linq;
using Microsoft.AspNetCore.Components;
using System.Collections.Generic;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class SiteService : ServiceBase, ISiteService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public SiteService(HttpClient http, IUriHelper urihelper)
public SiteService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "Site");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "Site"); }
}
public async Task<List<Site>> GetSitesAsync()

View File

@ -2,18 +2,24 @@
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Shared;
namespace Oqtane.Services
{
public class TenantService : ServiceBase, ITenantService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public TenantService(HttpClient http, IUriHelper urihelper)
public TenantService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "Tenant");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "Tenant"); }
}
public async Task<Tenant> GetTenantAsync()

View File

@ -13,48 +13,49 @@ namespace Oqtane.Services
public class ThemeService : ServiceBase, IThemeService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
private List<Theme> themes;
public ThemeService(HttpClient http, IUriHelper urihelper)
public ThemeService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "Theme");
this.sitestate = sitestate;
}
//TODO: Implement Caching or otherwise on this, and other calls within this class
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "Theme"); }
}
public async Task<List<Theme>> GetThemesAsync()
{
if (themes == null)
List<Theme> themes = await http.GetJsonAsync<List<Theme>>(apiurl);
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Theme theme in themes)
{
themes = await http.GetJsonAsync<List<Theme>>(apiurl);
// get list of loaded assemblies
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (Theme theme in themes)
if (theme.Dependencies != "")
{
if (theme.Dependencies != "")
foreach (string dependency in theme.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
foreach (string dependency in theme.Dependencies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
string assemblyname = dependency.Replace(".dll", "");
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
string assemblyname = dependency.Replace(".dll", "");
if (assemblies.Where(item => item.FullName.StartsWith(assemblyname + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + assemblyname + ".dll");
Assembly.Load(bytes);
}
}
if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + theme.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
if (assemblies.Where(item => item.FullName.StartsWith(theme.AssemblyName + ",")).FirstOrDefault() == null)
{
// download assembly from server and load
var bytes = await http.GetByteArrayAsync("_framework/_bin/" + theme.AssemblyName + ".dll");
Assembly.Load(bytes);
}
}
return themes.OrderBy(item => item.Name).ToList();
}

View File

@ -12,12 +12,17 @@ namespace Oqtane.Services
public class UserService : ServiceBase, IUserService
{
private readonly HttpClient http;
private readonly string apiurl;
private readonly SiteState sitestate;
public UserService(HttpClient http, IUriHelper urihelper)
public UserService(HttpClient http, SiteState sitestate)
{
this.http = http;
apiurl = CreateApiUrl(urihelper.GetAbsoluteUri(), "User");
this.sitestate = sitestate;
}
private string apiurl
{
get { return CreateApiUrl(sitestate.Alias, "User"); }
}
public async Task<List<User>> GetUsersAsync()

View File

@ -6,7 +6,10 @@ namespace Oqtane.Shared
{
public class PageState
{
public string Alias { get; set; }
public List<ModuleDefinition> ModuleDefinitions { get; set; }
public List<Theme> Themes { get; set; }
public List<Alias> Aliases { get; set; }
public Alias Alias { get; set; }
public Site Site { get; set; }
public List<Page> Pages { get; set; }
public Page Page { get; set; }
@ -16,6 +19,5 @@ namespace Oqtane.Shared
public Dictionary<string, string> QueryString { get; set; }
public int ModuleId { get; set; }
public string Control { get; set; }
public string Mode { get; set; }
}
}

View File

@ -5,8 +5,10 @@
@using System.Collections.Generic
@using Oqtane.Shared
@using Microsoft.JSInterop
@inject SiteState SiteState
@inject IUriHelper UriHelper
@inject IJSRuntime jsRuntime
@inject IAliasService AliasService
@inject ITenantService TenantService
@inject ISiteService SiteService
@inject IPageService PageService
@ -25,12 +27,6 @@
RenderFragment DynamicComponent { get; set; }
private string _absoluteUri;
string alias;
Site site;
List<Page> pages;
Page page;
User user;
List<Module> modules;
PageState pagestate;
protected override void OnInit()
@ -63,33 +59,51 @@
private async Task Refresh()
{
List<ModuleDefinition> moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
List<Models.Theme> themes = await ThemeService.GetThemesAsync();
List<ModuleDefinition> moduledefinitions;
List<Models.Theme> themes;
List<Alias> aliases;
Alias alias;
Site site;
List<Page> pages;
Page page;
User user;
List<Module> modules;
bool reload = false;
if (PageState == null)
{
Tenant tenant = await TenantService.GetTenantAsync();
site = await SiteService.GetSiteAsync(tenant.SiteId);
alias = Utilities.GetAlias(_absoluteUri);
aliases = await AliasService.GetAliasesAsync();
alias = null;
}
else
{
site = PageState.Site;
aliases = PageState.Aliases;
alias = PageState.Alias;
}
if (Utilities.GetAlias(_absoluteUri) != alias)
if (alias == null || GetAlias(_absoluteUri, aliases).Name != alias.Name)
{
Tenant tenant = await TenantService.GetTenantAsync();
site = await SiteService.GetSiteAsync(tenant.SiteId);
alias = Utilities.GetAlias(_absoluteUri);
alias = GetAlias(_absoluteUri, aliases);
SiteState.Alias = alias; // set state for services
reload = true;
}
if (site != null)
if (PageState == null || reload == true)
{
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
themes = await ThemeService.GetThemesAsync();
site = await SiteService.GetSiteAsync(alias.SiteId);
}
else
{
moduledefinitions = PageState.ModuleDefinitions;
themes = PageState.Themes;
site = PageState.Site;
}
if (site != null || reload == true)
{
var interop = new Interop(jsRuntime);
string userid = await interop.GetCookie("user");
user = null;
if (PageState == null || reload == true)
{
if (!string.IsNullOrEmpty(userid))
@ -120,9 +134,11 @@
}
string path = new Uri(_absoluteUri).PathAndQuery.Substring(1);
if (alias != "")
if (path.EndsWith("/")) { path = path.Substring(0, path.Length - 1); }
if (alias.Path != "")
{
path = path.Replace(alias, "");
path = path.Replace(alias.Path, "");
if (path.StartsWith("/")) { path = path.Substring(1); }
}
Dictionary<string, string> querystring = ParseQueryString(path);
@ -165,6 +181,9 @@
if (UserService.IsAuthorized(user, page.ViewPermissions))
{
pagestate = new PageState();
pagestate.ModuleDefinitions = moduledefinitions;
pagestate.Themes = themes;
pagestate.Aliases = aliases;
pagestate.Alias = alias;
pagestate.Site = site;
pagestate.Pages = pages;
@ -174,7 +193,6 @@
pagestate.QueryString = querystring;
pagestate.ModuleId = -1;
pagestate.Control = "";
pagestate.Mode = "client";
if (querystring.ContainsKey("mid"))
{
@ -309,4 +327,32 @@
return modules;
}
private Alias GetAlias(string absoluteUri, List<Alias> aliases)
{
string aliasname;
Alias alias = null;
Uri uri = new Uri(absoluteUri);
if (uri.Segments.Count() > 1)
{
// check if first path segment is an alias ( ie. a subfolder - www.domain.com/subfolder )
aliasname = uri.Authority + "/" + uri.Segments[1];
if (aliasname.EndsWith("/")) { aliasname = aliasname.Substring(0, aliasname.Length - 1); }
alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault();
}
if (alias == null)
{
aliasname = uri.Authority;
alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault();
}
if (alias == null && aliases.Count > 0)
{
// use first alias if Uri does not exist
alias = aliases.FirstOrDefault();
}
alias.Scheme = uri.Scheme;
return alias;
}
}

View File

@ -0,0 +1,11 @@
using Oqtane.Models;
namespace Oqtane.Shared
{
// this class is used for passing state between Blazor components and Services
public class SiteState
{
public Alias Alias { get; set; }
}
}

View File

@ -1,18 +1,52 @@
using System;
using Oqtane.Models;
namespace Oqtane.Shared
{
public class Utilities
{
public static string GetAlias(string absoluteUri)
public static string NavigateUrl(PageState pagestate)
{
string alias = "";
Uri uri = new Uri(absoluteUri);
if (uri.AbsolutePath.StartsWith("/~"))
return NavigateUrl(pagestate, pagestate.Page.Path, false);
}
public static string NavigateUrl(PageState pagestate, bool reload)
{
return NavigateUrl(pagestate, pagestate.Page.Path, reload);
}
public static string NavigateUrl(PageState pagestate, string path)
{
return NavigateUrl(pagestate, path, false);
}
public static string NavigateUrl(PageState pagestate, string path, bool reload)
{
string url = pagestate.Alias.Path + "/" + path;
if (reload)
{
alias = uri.Segments[1];
url += "?reload=true";
}
return alias;
return url;
}
public static string EditUrl(PageState pagestate, Module modulestate, string action)
{
return EditUrl(pagestate, modulestate, action, "");
}
public static string EditUrl(PageState pagestate, Module modulestate, string action, string parameters)
{
string url = pagestate.Alias.Path + "/" + pagestate.Page.Path + "?mid=" + modulestate.ModuleId.ToString();
if (action != "")
{
url += "&ctl=" + action;
}
if (!string.IsNullOrEmpty(parameters))
{
url += "&" + parameters;
}
return url;
}
public static string GetTypeNameClass(string typename)

View File

@ -1,5 +1,3 @@
#define ServerSideBlazor
using Microsoft.AspNetCore.Components.Builder;
using Microsoft.Extensions.DependencyInjection;
using System;
@ -9,6 +7,7 @@ using System.Net.Http;
using Microsoft.AspNetCore.Components;
using System.Reflection;
using Oqtane.Modules;
using Oqtane.Shared;
namespace Oqtane.Client
{
@ -28,11 +27,11 @@ namespace Oqtane.Client
#if WASM
public void ConfigureServices(IServiceCollection services)
{
// register singleton core services
services.AddSingleton<IModuleDefinitionService, ModuleDefinitionService>();
services.AddSingleton<IThemeService, ThemeService>();
// register scoped core services
services.AddScoped<SiteState>();
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
services.AddScoped<IThemeService, ThemeService>();
services.AddScoped<IAliasService, AliasService>();
services.AddScoped<ITenantService, TenantService>();
services.AddScoped<ISiteService, SiteService>();
services.AddScoped<IPageService, PageService>();

View File

@ -25,7 +25,7 @@
protected override void OnInit()
{
closeurl = PageState.Alias + PageState.Page.Path;
closeurl = NavigateUrl();
}
}

View File

@ -13,5 +13,35 @@ namespace Oqtane.Themes
protected Module ModuleState { get; set; }
public virtual string Name { get; set; }
public string NavigateUrl()
{
return Utilities.NavigateUrl(PageState);
}
public string NavigateUrl(bool reload)
{
return Utilities.NavigateUrl(PageState, reload);
}
public string NavigateUrl(string path)
{
return Utilities.NavigateUrl(PageState, path);
}
public string NavigateUrl(string path, bool reload)
{
return Utilities.NavigateUrl(PageState, path, reload);
}
public string EditUrl(string action)
{
return Utilities.EditUrl(PageState, ModuleState, action, "");
}
public string EditUrl(string action, string parameters)
{
return Utilities.EditUrl(PageState, ModuleState, action, parameters);
}
}
}

View File

@ -74,7 +74,7 @@
string display = "display: none";
List<ModuleDefinition> moduledefinitions;
Dictionary<string, string> containers = new Dictionary<string, string>();
int pagemanagementmoduleid;
int pagemanagementmoduleid = -1;
string moduledefinitionname;
string pane;
string title = "";
@ -82,11 +82,13 @@
protected override async Task OnInitAsync()
{
//TODO: Move this to shared component. This is used in this control Add, Edit, and Delete controls as well
moduledefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync();
containers = ThemeService.GetContainerTypes(await ThemeService.GetThemesAsync());
moduledefinitions = PageState.ModuleDefinitions;
containers = ThemeService.GetContainerTypes(PageState.Themes);
List<Module> modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId, Constants.PageManagementModule);
pagemanagementmoduleid = modules.FirstOrDefault().ModuleId;
if (modules.Count > 0)
{
pagemanagementmoduleid = modules.FirstOrDefault().ModuleId;
}
if (UserService.IsAuthorized(PageState.User, PageState.Page.EditPermissions))
{
display = "display: inline";
@ -117,23 +119,26 @@
pagemodule.Order = 0;
pagemodule.ContainerType = containertype;
await PageModuleService.AddPageModuleAsync(pagemodule);
UriHelper.NavigateTo(PageState.Alias + PageState.Page.Path + "?reload=true");
UriHelper.NavigateTo(NavigateUrl(true));
}
private string PageUrl(string action)
{
string url = "";
switch (action)
if (pagemanagementmoduleid != -1)
{
case "Add":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action;
break;
case "Edit":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action + "&id=" + PageState.Page.PageId.ToString();
break;
case "Delete":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action + "&id=" + PageState.Page.PageId.ToString();
break;
switch (action)
{
case "Add":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action;
break;
case "Edit":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action + "&id=" + PageState.Page.PageId.ToString();
break;
case "Delete":
url = "admin/pages?mid=" + pagemanagementmoduleid.ToString() + "&ctl=" + action + "&id=" + PageState.Page.PageId.ToString();
break;
}
}
return url;
}

View File

@ -29,13 +29,13 @@
{
if (name == "Login")
{
UriHelper.NavigateTo(PageState.Alias + "login");
UriHelper.NavigateTo(NavigateUrl("login"));
}
else
{
var interop = new Interop(jsRuntime);
await interop.SetCookie("user", "", 7);
UriHelper.NavigateTo(PageState.Alias, true);
UriHelper.NavigateTo(NavigateUrl(""), true);
}
}
}

View File

@ -1,5 +1,5 @@
@using Oqtane.Themes
@inherits ThemeObjectBase
<a href="@PageState.Uri.Scheme://@PageState.Uri.Authority"><img src="/Sites/@PageState.Site.SiteId/@PageState.Site.Logo" /></a>
<a href="@PageState.Alias.Url"><img src="/Sites/@PageState.Site.SiteId/@PageState.Site.Logo" /></a>

View File

@ -9,7 +9,7 @@
<ul class="nav flex-column">
@if (parent != null)
{
string url = PageState.Alias + parent.Path;
string url = NavigateUrl();
<li class="nav-item px-3">
<NavLink class="nav-link" href="@parent.Path" Match="NavLinkMatch.All">
<span class="oi oi-media-skip-backward" aria-hidden="true"></span> Back
@ -20,7 +20,7 @@
{
if (p.IsNavigation && UserService.IsAuthorized(PageState.User, p.ViewPermissions))
{
string url = PageState.Alias + p.Path;
string url = NavigateUrl(p.Path);
<li class="nav-item px-3">
<NavLink class="nav-link" href="@url" Match="NavLinkMatch.All">
<span class="oi @p.Icon" aria-hidden="true"></span> @p.Name

View File

@ -1,44 +0,0 @@
@using Oqtane.Themes
@using Oqtane.Shared;
@using Microsoft.JSInterop
@inject IJSRuntime jsRuntime
@inherits ThemeObjectBase
<button type="button" class="btn btn-primary" onclick="@SetMode">
@displayMode
</button>
@functions {
string displayMode = "";
protected override async Task OnInitAsync()
{
var interop = new Interop(jsRuntime);
string value = await interop.GetCookie("blazor");
if (value == "client")
{
displayMode = "Server Mode";
}
else
{
displayMode = "Client Mode";
}
}
public async void SetMode()
{
var interop = new Interop(jsRuntime);
string mode = await interop.GetCookie("blazor");
if (mode == "client")
{
mode = "server";
}
else
{
mode = "client";
}
await interop.SetCookie("blazor", mode, 7);
}
}

View File

@ -81,7 +81,7 @@
await PageModuleService.UpdatePageModuleAsync(pagemodule);
break;
}
UriHelper.NavigateTo(PageState.Alias + path);
UriHelper.NavigateTo(NavigateUrl(path));
}
public class ActionViewModel

View File

@ -9,5 +9,26 @@ namespace Oqtane.Themes
protected PageState PageState { get; set; }
public virtual string Name { get; set; }
public virtual string Panes { get; set; }
public string NavigateUrl()
{
return Utilities.NavigateUrl(PageState);
}
public string NavigateUrl(bool reload)
{
return Utilities.NavigateUrl(PageState, reload);
}
public string NavigateUrl(string path)
{
return Utilities.NavigateUrl(PageState, path);
}
public string NavigateUrl(string path, bool reload)
{
return Utilities.NavigateUrl(PageState, path, reload);
}
}
}

View File

@ -7,5 +7,25 @@ namespace Oqtane.Themes
{
[CascadingParameter]
protected PageState PageState { get; set; }
public string NavigateUrl()
{
return Utilities.NavigateUrl(PageState);
}
public string NavigateUrl(bool reload)
{
return Utilities.NavigateUrl(PageState, reload);
}
public string NavigateUrl(string path)
{
return Utilities.NavigateUrl(PageState, path);
}
public string NavigateUrl(string path, bool reload)
{
return Utilities.NavigateUrl(PageState, path, reload);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

View File

@ -21,15 +21,7 @@
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script id="blazor"></script>
<script>
var src = "_framework/blazor.webassembly.js";
var blazor = getCookie("blazor");
if (blazor === "server") {
src = "_framework/components.server.js";
}
document.getElementById("blazor").src = src;
</script>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>

View File

@ -1,20 +1,3 @@
/* called by index.html to check if mode is set */
function getCookie(name) {
name = name + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) === ' ') {
c = c.substring(1);
}
if (c.indexOf(name) === 0) {
return c.substring(name.length, c.length);
}
}
return "";
}
/* Open when someone clicks on the span element */
function openActions() {
document.getElementById("actions").style.width = "25%";

View File

@ -0,0 +1,55 @@
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Oqtane.Repository;
using Oqtane.Models;
namespace Oqtane.Controllers
{
[Route("{site}/api/[controller]")]
public class AliasController : Controller
{
private readonly IAliasRepository aliases;
public AliasController(IAliasRepository Aliases)
{
aliases = Aliases;
}
// GET: api/<controller>
[HttpGet]
public IEnumerable<Alias> Get()
{
return aliases.GetAliases();
}
// GET api/<controller>/5
[HttpGet("{id}")]
public Alias Get(int id)
{
return aliases.GetAlias(id);
}
// POST api/<controller>
[HttpPost]
public void Post([FromBody] Alias site)
{
if (ModelState.IsValid)
aliases.AddAlias(site);
}
// PUT api/<controller>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] Alias site)
{
if (ModelState.IsValid)
aliases.UpdateAlias(site);
}
// DELETE api/<controller>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
aliases.DeleteAlias(id);
}
}
}

View File

@ -1,6 +1,7 @@
using Microsoft.AspNetCore.Mvc;
using Oqtane.Repository;
using Oqtane.Models;
using System.Collections.Generic;
namespace Oqtane.Controllers
{
@ -16,9 +17,39 @@ namespace Oqtane.Controllers
// GET: api/<controller>
[HttpGet]
public Tenant Get()
public IEnumerable<Tenant> Get()
{
return tenants.GetTenant();
return tenants.GetTenants();
}
// GET api/<controller>/5
[HttpGet("{id}")]
public Tenant Get(int id)
{
return tenants.GetTenant(id);
}
// POST api/<controller>
[HttpPost]
public void Post([FromBody] Tenant site)
{
if (ModelState.IsValid)
tenants.AddTenant(site);
}
// PUT api/<controller>/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] Tenant site)
{
if (ModelState.IsValid)
tenants.UpdateTenant(site);
}
// DELETE api/<controller>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
tenants.DeleteTenant(id);
}
}
}

View File

@ -1,5 +1,4 @@
using Microsoft.EntityFrameworkCore;
using Oqtane.Models;
using Oqtane.Shared.Modules.HtmlText.Models;
using Oqtane.Repository;
using Oqtane.Modules;
@ -10,7 +9,7 @@ namespace Oqtane.Server.Modules.HtmlText.Repository
{
public virtual DbSet<HtmlTextInfo> HtmlText { get; set; }
public HtmlTextContext(ITenantRepository TenantRepository):base(TenantRepository)
public HtmlTextContext(ITenantResolver TenantResolver):base(TenantResolver)
{
// ContextBase handles multi-tenant database connections
}

View File

@ -0,0 +1,91 @@
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using System;
namespace Oqtane.Repository
{
public class AliasRepository : IAliasRepository
{
private HostContext db;
private readonly IMemoryCache _cache;
public AliasRepository(HostContext context, IMemoryCache cache)
{
db = context;
_cache = cache;
}
public IEnumerable<Alias> GetAliases()
{
try
{
IEnumerable<Alias> aliases = _cache.GetOrCreate("aliases", entry =>
{
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
return db.Alias.ToList();
});
return aliases;
}
catch
{
throw;
}
}
public void AddAlias(Alias alias)
{
try
{
db.Alias.Add(alias);
db.SaveChanges();
}
catch
{
throw;
}
}
public void UpdateAlias(Alias alias)
{
try
{
db.Entry(alias).State = EntityState.Modified;
db.SaveChanges();
}
catch
{
throw;
}
}
public Alias GetAlias(int aliasId)
{
try
{
Alias alias = db.Alias.Find(aliasId);
return alias;
}
catch
{
throw;
}
}
public void DeleteAlias(int aliasId)
{
try
{
Alias alias = db.Alias.Find(aliasId);
db.Alias.Remove(alias);
db.SaveChanges();
}
catch
{
throw;
}
}
}
}

View File

@ -8,9 +8,9 @@ namespace Oqtane.Repository
{
private Tenant tenant;
public ContextBase(ITenantRepository TenantRepository)
public ContextBase(ITenantResolver TenantResolver)
{
tenant = TenantRepository.GetTenant();
tenant = TenantResolver.GetTenant();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@ -7,6 +7,7 @@ namespace Oqtane.Repository
{
public HostContext(DbContextOptions<HostContext> options) : base(options) { }
public virtual DbSet<Alias> Alias { get; set; }
public virtual DbSet<Tenant> Tenant { get; set; }
}
}

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using Oqtane.Models;
namespace Oqtane.Repository
{
public interface IAliasRepository
{
IEnumerable<Alias> GetAliases();
void AddAlias(Alias alias);
void UpdateAlias(Alias alias);
Alias GetAlias(int aliasId);
void DeleteAlias(int aliasId);
}
}

View File

@ -1,9 +1,14 @@
using Oqtane.Models;
using System.Collections.Generic;
namespace Oqtane.Repository
{
public interface ITenantRepository
{
Tenant GetTenant();
IEnumerable<Tenant> GetTenants();
void AddTenant(Tenant tenant);
void UpdateTenant(Tenant tenant);
Tenant GetTenant(int tenantId);
void DeleteTenant(int tenantId);
}
}

View File

@ -0,0 +1,9 @@
using Oqtane.Models;
namespace Oqtane.Repository
{
public interface ITenantResolver
{
Tenant GetTenant();
}
}

View File

@ -14,9 +14,9 @@ namespace Oqtane.Repository
private readonly Tenant tenant;
public TenantContext(ITenantRepository TenantRepository)
public TenantContext(ITenantResolver TenantResolver)
{
tenant = TenantRepository.GetTenant();
tenant = TenantResolver.GetTenant();
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)

View File

@ -4,6 +4,7 @@ using System.Linq;
using Oqtane.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.EntityFrameworkCore;
namespace Oqtane.Repository
{
@ -11,23 +12,14 @@ namespace Oqtane.Repository
{
private HostContext db;
private readonly IMemoryCache _cache;
private readonly string alias;
public TenantRepository(HostContext context, IMemoryCache cache, IHttpContextAccessor accessor)
public TenantRepository(HostContext context, IMemoryCache cache)
{
db = context;
_cache = cache;
// get site alias based on request context
alias = accessor.HttpContext.Request.Host.Value;
string path = accessor.HttpContext.Request.Path.Value;
if (path.StartsWith("/~") && !path.StartsWith("/~/"))
{
alias += path.Substring(0, path.IndexOf("/", 1));
}
}
public Tenant GetTenant()
public IEnumerable<Tenant> GetTenants()
{
try
{
@ -36,15 +28,45 @@ namespace Oqtane.Repository
entry.SlidingExpiration = TimeSpan.FromMinutes(30);
return db.Tenant.ToList();
});
Tenant tenant;
if (tenants.Count() == 1)
{
tenant = tenants.FirstOrDefault();
}
else
{
tenant = tenants.Where(item => item.Alias == alias).FirstOrDefault();
}
return tenants;
}
catch
{
throw;
}
}
public void AddTenant(Tenant tenant)
{
try
{
db.Tenant.Add(tenant);
db.SaveChanges();
}
catch
{
throw;
}
}
public void UpdateTenant(Tenant tenant)
{
try
{
db.Entry(tenant).State = EntityState.Modified;
db.SaveChanges();
}
catch
{
throw;
}
}
public Tenant GetTenant(int tenantId)
{
try
{
Tenant tenant = db.Tenant.Find(tenantId);
return tenant;
}
catch
@ -52,5 +74,19 @@ namespace Oqtane.Repository
throw;
}
}
public void DeleteTenant(int tenantId)
{
try
{
Tenant tenant = db.Tenant.Find(tenantId);
db.Tenant.Remove(tenant);
db.SaveChanges();
}
catch
{
throw;
}
}
}
}

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Caching.Memory;
namespace Oqtane.Repository
{
public class TenantResolver : ITenantResolver
{
private HostContext db;
private readonly string aliasname;
private readonly IAliasRepository _aliasrepository;
private readonly ITenantRepository _tenantrepository;
public TenantResolver(HostContext context, IHttpContextAccessor accessor, IAliasRepository aliasrepository, ITenantRepository tenantrepository)
{
db = context;
_aliasrepository = aliasrepository;
_tenantrepository = tenantrepository;
// get alias based on request context
aliasname = accessor.HttpContext.Request.Host.Value;
string path = accessor.HttpContext.Request.Path.Value;
string[] segments = path.Split('/');
if (segments[1] != "~")
{
aliasname += "/" + segments[1];
}
}
public Tenant GetTenant()
{
try
{
IEnumerable<Alias> aliases = _aliasrepository.GetAliases(); // cached
Alias alias = aliases.Where(item => item.Name == aliasname).FirstOrDefault();
IEnumerable<Tenant> tenants = _tenantrepository.GetTenants(); // cached
return tenants.Where(item => item.TenantId == alias.TenantId).FirstOrDefault();
}
catch
{
throw;
}
}
}
}

View File

@ -3,12 +3,23 @@
Create tables
*/
CREATE TABLE [dbo].[Alias](
[AliasId] [int] IDENTITY(1,1) NOT NULL,
[Name] [nvarchar](200) NOT NULL,
[TenantId] [int] NOT NULL,
[SiteId] [int] NOT NULL,
CONSTRAINT [PK_Alias] PRIMARY KEY CLUSTERED
(
[AliasId] ASC
)
)
GO
CREATE TABLE [dbo].[Tenant](
[TenantId] [int] IDENTITY(1,1) NOT NULL,
[Alias] [nvarchar](200) NOT NULL,
[Name] [nvarchar](100) NOT NULL,
[DBConnectionString] [nvarchar](1024) NOT NULL,
[DBSchema] [nvarchar](50) NOT NULL,
[SiteId] [int] NOT NULL,
[DBSchema] [nvarchar](50) NOT NULL
CONSTRAINT [PK_Tenant] PRIMARY KEY CLUSTERED
(
[TenantId] ASC
@ -102,7 +113,7 @@ GO
/*
Create relationships
Create foreign key relationships
*/
ALTER TABLE [dbo].[HtmlText] WITH CHECK ADD CONSTRAINT [FK_HtmlText_Module] FOREIGN KEY([ModuleId])
@ -110,38 +121,28 @@ REFERENCES [dbo].[Module] ([ModuleId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[HtmlText] CHECK CONSTRAINT [FK_HtmlText_Module]
GO
ALTER TABLE [dbo].[Module] WITH CHECK ADD CONSTRAINT [FK_Module_Site] FOREIGN KEY([SiteId])
REFERENCES [dbo].[Site] ([SiteId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Module] CHECK CONSTRAINT [FK_Module_Site]
GO
ALTER TABLE [dbo].[Page] WITH CHECK ADD CONSTRAINT [FK_Page_Site] FOREIGN KEY([SiteId])
REFERENCES [dbo].[Site] ([SiteId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Page] CHECK CONSTRAINT [FK_Page_Site]
GO
ALTER TABLE [dbo].[PageModule] WITH CHECK ADD CONSTRAINT [FK_PageModule_Module] FOREIGN KEY([ModuleId])
REFERENCES [dbo].[Module] ([ModuleId])
GO
ALTER TABLE [dbo].[PageModule] CHECK CONSTRAINT [FK_PageModule_Module]
GO
ALTER TABLE [dbo].[PageModule] WITH CHECK ADD CONSTRAINT [FK_PageModule_Page] FOREIGN KEY([PageId])
REFERENCES [dbo].[Page] ([PageId])
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[PageModule] CHECK CONSTRAINT [FK_PageModule_Page]
ALTER TABLE [dbo].[Alias] WITH CHECK ADD CONSTRAINT [FK_Alias_Tenant] FOREIGN KEY([TenantId])
REFERENCES [dbo].[Tenant] ([TenantId])
ON DELETE CASCADE
GO
/*
@ -151,17 +152,31 @@ Create seed data
*/
SET IDENTITY_INSERT [dbo].[Tenant] ON
GO
INSERT [dbo].[Tenant] ([TenantId], [Alias], [DBConnectionString], [DBSchema], [SiteId])
VALUES (1, N'localhost:44357', N'{ConnectionString}', N'', 1)
INSERT [dbo].[Tenant] ([TenantId], [Name], [DBConnectionString], [DBSchema])
VALUES (1, N'Tenant1', N'{ConnectionString}', N'')
GO
SET IDENTITY_INSERT [dbo].[Tenant] OFF
GO
SET IDENTITY_INSERT [dbo].[Alias] ON
GO
INSERT [dbo].[Alias] ([AliasId], [Name], [TenantId], [SiteId])
VALUES (1, N'localhost:44357', 1, 1)
GO
INSERT [dbo].[Alias] ([AliasId], [Name], [TenantId], [SiteId])
VALUES (2, N'localhost:44357/site2', 1, 2)
GO
SET IDENTITY_INSERT [dbo].[Alias] OFF
GO
SET IDENTITY_INSERT [dbo].[Site] ON
GO
INSERT [dbo].[Site] ([SiteId], [Name], [Logo])
VALUES (1, N'Site1', N'oqtane.png')
GO
INSERT [dbo].[Site] ([SiteId], [Name], [Logo])
VALUES (2, N'Site2', N'oqtane.png')
GO
SET IDENTITY_INSERT [dbo].[Site] OFF
GO
@ -200,6 +215,12 @@ GO
INSERT [dbo].[Page] ([PageId], [SiteId], [Name], [Path], [ThemeType], [Icon], [Panes], [ViewPermissions], [EditPermissions], [ParentId], [Order], [IsNavigation], [LayoutType])
VALUES (11, 1, N'Theme Management', N'admin/themes', N'Oqtane.Client.Themes.Theme2.Theme2, Oqtane.Client', N'', N'Top;Bottom', N'Administrators', N'Administrators', 4, 4, 1, N'')
GO
INSERT [dbo].[Page] ([PageId], [SiteId], [Name], [Path], [ThemeType], [Icon], [Panes], [ViewPermissions], [EditPermissions], [ParentId], [Order], [IsNavigation], [LayoutType])
VALUES (12, 2, N'Page1', N'', N'Oqtane.Client.Themes.Theme2.Theme2, Oqtane.Client', N'oi-home', N'Top;Bottom', N'All Users', N'Administrators', NULL, 1, 1, N'')
GO
INSERT [dbo].[Page] ([PageId], [SiteId], [Name], [Path], [ThemeType], [Icon], [Panes], [ViewPermissions], [EditPermissions], [ParentId], [Order], [IsNavigation], [LayoutType])
VALUES (13, 2, N'Page2', N'page2', N'Oqtane.Client.Themes.Theme2.Theme2, Oqtane.Client', N'oi-home', N'Top;Bottom', N'All Users', N'Administrators', NULL, 1, 1, N'')
GO
SET IDENTITY_INSERT [dbo].[Page] OFF
GO
@ -250,6 +271,12 @@ GO
INSERT [dbo].[Module] ([ModuleId], [SiteId], [ModuleDefinitionName], [ViewPermissions], [EditPermissions])
VALUES (15, 1, N'Oqtane.Client.Modules.Admin.Themes, Oqtane.Client', N'Administrators', N'Administrators')
GO
INSERT [dbo].[Module] ([ModuleId], [SiteId], [ModuleDefinitionName], [ViewPermissions], [EditPermissions])
VALUES (16, 2, N'Oqtane.Client.Modules.HtmlText, Oqtane.Client', N'All Users', N'Administrators')
GO
INSERT [dbo].[Module] ([ModuleId], [SiteId], [ModuleDefinitionName], [ViewPermissions], [EditPermissions])
VALUES (17, 2, N'Oqtane.Client.Modules.HtmlText, Oqtane.Client', N'All Users', N'Administrators')
GO
SET IDENTITY_INSERT [dbo].[Module] OFF
GO
@ -300,13 +327,19 @@ GO
INSERT [dbo].[PageModule] ([PageModuleId], [PageId], [ModuleId], [Title], [Pane], [Order], [ContainerType])
VALUES (15, 11, 15, N'Theme Management', N'Top', 0, N'Oqtane.Client.Themes.Theme2.Container2, Oqtane.Client')
GO
INSERT [dbo].[PageModule] ([PageModuleId], [PageId], [ModuleId], [Title], [Pane], [Order], [ContainerType])
VALUES (16, 12, 16, N'Text', N'Top', 1, N'Oqtane.Client.Themes.Theme2.Container2, Oqtane.Client')
GO
INSERT [dbo].[PageModule] ([PageModuleId], [PageId], [ModuleId], [Title], [Pane], [Order], [ContainerType])
VALUES (17, 13, 17, N'Text', N'Top', 1, N'Oqtane.Client.Themes.Theme2.Container2, Oqtane.Client')
GO
SET IDENTITY_INSERT [dbo].[PageModule] OFF
GO
SET IDENTITY_INSERT [dbo].[HtmlText] ON
GO
INSERT [dbo].[HtmlText] ([HtmlTextId], [ModuleId], [Content])
VALUES (1, 3, N'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.')
VALUES (1, 3, N'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. <br /><br /><a href="http://localhost:44357/site2/">Go To Site2</a>')
GO
INSERT [dbo].[HtmlText] ([HtmlTextId], [ModuleId], [Content])
VALUES (2, 5, N'Enim sed faucibus turpis in eu mi bibendum neque egestas. Quis hendrerit dolor magna eget est lorem. Dui faucibus in ornare quam viverra orci sagittis. Integer eget aliquet nibh praesent tristique magna sit. Nunc aliquet bibendum enim facilisis gravida neque convallis a cras. Tortor id aliquet lectus proin. Diam volutpat commodo sed egestas egestas fringilla. Posuere sollicitudin aliquam ultrices sagittis orci. Viverra mauris in aliquam sem fringilla ut morbi tincidunt. Eget gravida cum sociis natoque penatibus et. Sagittis orci a scelerisque purus semper. Eget velit aliquet sagittis id consectetur purus. Volutpat blandit aliquam etiam erat. Et tortor consequat id porta nibh venenatis cras. Volutpat odio facilisis mauris sit amet. Varius duis at consectetur lorem.')
@ -317,6 +350,12 @@ GO
INSERT [dbo].[HtmlText] ([HtmlTextId], [ModuleId], [Content])
VALUES (4, 7, N'Ornare arcu dui vivamus arcu felis bibendum ut. Tortor vitae purus faucibus ornare. Lectus sit amet est placerat in egestas erat imperdiet sed. Aliquam sem et tortor consequat id. Fermentum iaculis eu non diam phasellus vestibulum. Ultricies integer quis auctor elit sed. Fermentum odio eu feugiat pretium nibh ipsum. Ut consequat semper viverra nam libero. Blandit aliquam etiam erat velit scelerisque in dictum non consectetur. At risus viverra adipiscing at in tellus. Facilisi nullam vehicula ipsum a arcu cursus vitae congue. At varius vel pharetra vel turpis nunc eget lorem dolor. Morbi non arcu risus quis varius. Turpis massa sed elementum tempus egestas.')
GO
INSERT [dbo].[HtmlText] ([HtmlTextId], [ModuleId], [Content])
VALUES (5, 16, N'Id consectetur purus ut faucibus pulvinar elementum integer. Bibendum neque egestas congue quisque egestas diam in arcu. Eget nullam non nisi est sit amet facilisis. Sit amet consectetur adipiscing elit pellentesque. Id aliquet risus feugiat in. Enim blandit volutpat maecenas volutpat blandit aliquam etiam erat. Commodo odio aenean sed adipiscing. Pharetra massa massa ultricies mi quis hendrerit dolor magna. Aliquet enim tortor at auctor urna nunc. Nulla pellentesque dignissim enim sit amet. Suscipit adipiscing bibendum est ultricies integer quis auctor. Lacinia quis vel eros donec ac odio tempor. Aliquam vestibulum morbi blandit cursus risus at. <br /><br /><a href="http://localhost:44357/">Go To Site1</a>')
GO
INSERT [dbo].[HtmlText] ([HtmlTextId], [ModuleId], [Content])
VALUES (6, 17, N'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.')
GO
SET IDENTITY_INSERT [dbo].[HtmlText] OFF
GO

View File

@ -18,6 +18,7 @@ using Oqtane.Services;
using System.Net.Http;
using Microsoft.AspNetCore.Components;
using Oqtane.Client;
using Oqtane.Shared;
namespace Oqtane.Server
{
@ -57,11 +58,11 @@ namespace Oqtane.Server
});
}
// register singleton core services
// register scoped core services
services.AddScoped<SiteState>();
services.AddScoped<IModuleDefinitionService, ModuleDefinitionService>();
services.AddScoped<IThemeService, ThemeService>();
// register scoped core services
services.AddScoped<IAliasService, AliasService>();
services.AddScoped<ITenantService, TenantService>();
services.AddScoped<ISiteService, SiteService>();
services.AddScoped<IPageService, PageService>();
@ -110,6 +111,8 @@ namespace Oqtane.Server
services.AddSingleton<IThemeRepository, ThemeRepository>();
// register transient scoped core services
services.AddTransient<ITenantResolver, TenantResolver>();
services.AddTransient<IAliasRepository, AliasRepository>();
services.AddTransient<ITenantRepository, TenantRepository>();
services.AddTransient<ISiteRepository, SiteRepository>();
services.AddTransient<IPageRepository, PageRepository>();

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,41 @@
using System.ComponentModel.DataAnnotations.Schema;
namespace Oqtane.Models
{
public class Alias
{
public int AliasId { get; set; }
public string Name { get; set; }
public int TenantId { get; set; }
public int SiteId { get; set; }
[NotMapped]
public string Scheme { get; set; }
[NotMapped]
public string Url
{
get
{
return Scheme + "://" + Name;
}
}
[NotMapped]
public string Path
{
get
{
if (Name.Contains("/"))
{
return Name.Substring(Name.IndexOf("/") + 1);
}
else
{
return "";
}
}
}
}
}

View File

@ -1,6 +1,4 @@
using System.Collections.Generic;
namespace Oqtane.Models
namespace Oqtane.Models
{
public class Page
{

View File

@ -5,9 +5,8 @@ namespace Oqtane.Models
public class Tenant
{
public int TenantId { get; set; }
public string Alias { get; set; }
public string Name { get; set; }
public string DBConnectionString { get; set; }
public string DBSchema { get; set; }
public int SiteId { get; set; }
}
}